blob: 8d98f8995e5ce3cc56e3e9bf631cfcfa2f797da3 [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;
26import android.provider.Browser;
27import android.util.Log;
28import android.webkit.WebIconDatabase;
29import android.widget.Toast;
30
Ben Murdochaac7aa62009-09-17 16:57:40 +010031import java.io.ByteArrayOutputStream;
Leon Scrogginse372c022009-06-12 17:07:29 -040032import java.util.Date;
33
34/**
35 * This class is purely to have a common place for adding/deleting bookmarks.
36 */
37/* package */ class Bookmarks {
38 private static final String WHERE_CLAUSE
39 = "url = ? OR url = ? OR url = ? OR url = ?";
40 private static final String WHERE_CLAUSE_SECURE = "url = ? OR url = ?";
41
42 private static String[] SELECTION_ARGS;
43
Ben Murdochde353622009-10-12 10:29:00 +010044 // We only want the user to be able to bookmark content that
45 // the browser can handle directly.
46 private static final String acceptableBookmarkSchemes[] = {
47 "http:",
48 "https:",
49 "about:",
50 "data:",
51 "javascript:",
52 "file:",
53 "content:"
54 };
55
Leon Scrogginse372c022009-06-12 17:07:29 -040056 /**
57 * Add a bookmark to the database.
58 * @param context Context of the calling Activity. This is used to make
59 * Toast confirming that the bookmark has been added. If the
60 * caller provides null, the Toast will not be shown.
61 * @param cr The ContentResolver being used to add the bookmark to the db.
62 * @param url URL of the website to be bookmarked.
63 * @param name Provided name for the bookmark.
Ben Murdochaac7aa62009-09-17 16:57:40 +010064 * @param thumbnail A thumbnail for the bookmark.
Christopher Tate9c0dd8c2009-07-10 17:51:48 -070065 * @param retainIcon Whether to retain the page's icon in the icon database.
66 * This will usually be <code>true</code> except when bookmarks are
67 * added by a settings restore agent.
Leon Scrogginse372c022009-06-12 17:07:29 -040068 */
69 /* package */ static void addBookmark(Context context,
Christopher Tate9c0dd8c2009-07-10 17:51:48 -070070 ContentResolver cr, String url, String name,
Ben Murdochaac7aa62009-09-17 16:57:40 +010071 Bitmap thumbnail, boolean retainIcon) {
Leon Scrogginse372c022009-06-12 17:07:29 -040072 // Want to append to the beginning of the list
73 long creationTime = new Date().getTime();
74 // First we check to see if the user has already visited this
75 // site. They may have bookmarked it in a different way from
76 // how it's stored in the database, so allow different combos
77 // to map to the same url.
78 boolean secure = false;
79 String compareString = url;
80 if (compareString.startsWith("http://")) {
81 compareString = compareString.substring(7);
82 } else if (compareString.startsWith("https://")) {
83 compareString = compareString.substring(8);
84 secure = true;
85 }
86 if (compareString.startsWith("www.")) {
87 compareString = compareString.substring(4);
88 }
89 if (secure) {
90 SELECTION_ARGS = new String[2];
91 SELECTION_ARGS[0] = "https://" + compareString;
92 SELECTION_ARGS[1] = "https://www." + compareString;
93 } else {
94 SELECTION_ARGS = new String[4];
95 SELECTION_ARGS[0] = compareString;
96 SELECTION_ARGS[1] = "www." + compareString;
97 SELECTION_ARGS[2] = "http://" + compareString;
98 SELECTION_ARGS[3] = "http://" + SELECTION_ARGS[1];
99 }
100 Cursor cursor = cr.query(Browser.BOOKMARKS_URI,
101 Browser.HISTORY_PROJECTION,
102 secure ? WHERE_CLAUSE_SECURE : WHERE_CLAUSE,
103 SELECTION_ARGS,
104 null);
105 ContentValues map = new ContentValues();
106 if (cursor.moveToFirst() && cursor.getInt(
107 Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) == 0) {
108 // This means we have been to this site but not bookmarked
109 // it, so convert the history item to a bookmark
110 map.put(Browser.BookmarkColumns.CREATED, creationTime);
111 map.put(Browser.BookmarkColumns.TITLE, name);
112 map.put(Browser.BookmarkColumns.BOOKMARK, 1);
Ben Murdochaac7aa62009-09-17 16:57:40 +0100113 map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
Leon Scrogginse372c022009-06-12 17:07:29 -0400114 cr.update(Browser.BOOKMARKS_URI, map,
115 "_id = " + cursor.getInt(0), null);
116 } else {
117 int count = cursor.getCount();
118 boolean matchedTitle = false;
119 for (int i = 0; i < count; i++) {
120 // One or more bookmarks already exist for this site.
121 // Check the names of each
122 cursor.moveToPosition(i);
123 if (cursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX)
124 .equals(name)) {
125 // The old bookmark has the same name.
126 // Update its creation time.
127 map.put(Browser.BookmarkColumns.CREATED,
128 creationTime);
129 cr.update(Browser.BOOKMARKS_URI, map,
130 "_id = " + cursor.getInt(0), null);
131 matchedTitle = true;
132 break;
133 }
134 }
135 if (!matchedTitle) {
136 // Adding a bookmark for a site the user has visited,
137 // or a new bookmark (with a different name) for a site
138 // the user has visited
139 map.put(Browser.BookmarkColumns.TITLE, name);
140 map.put(Browser.BookmarkColumns.URL, url);
141 map.put(Browser.BookmarkColumns.CREATED, creationTime);
142 map.put(Browser.BookmarkColumns.BOOKMARK, 1);
143 map.put(Browser.BookmarkColumns.DATE, 0);
Ben Murdochaac7aa62009-09-17 16:57:40 +0100144 map.put(Browser.BookmarkColumns.THUMBNAIL, bitmapToBytes(thumbnail));
Leon Scrogginse372c022009-06-12 17:07:29 -0400145 int visits = 0;
146 if (count > 0) {
147 // The user has already bookmarked, and possibly
148 // visited this site. However, they are creating
149 // a new bookmark with the same url but a different
150 // name. The new bookmark should have the same
151 // number of visits as the already created bookmark.
152 visits = cursor.getInt(
153 Browser.HISTORY_PROJECTION_VISITS_INDEX);
154 }
155 // Bookmark starts with 3 extra visits so that it will
156 // bubble up in the most visited and goto search box
157 map.put(Browser.BookmarkColumns.VISITS, visits + 3);
158 cr.insert(Browser.BOOKMARKS_URI, map);
159 }
160 }
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700161 if (retainIcon) {
162 WebIconDatabase.getInstance().retainIconForPageUrl(url);
163 }
Leon Scrogginse372c022009-06-12 17:07:29 -0400164 cursor.deactivate();
165 if (context != null) {
166 Toast.makeText(context, R.string.added_to_bookmarks,
167 Toast.LENGTH_LONG).show();
168 }
169 }
170
171 /**
172 * Remove a bookmark from the database. If the url is a visited site, it
173 * will remain in the database, but only as a history item, and not as a
174 * bookmarked site.
175 * @param context Context of the calling Activity. This is used to make
176 * Toast confirming that the bookmark has been removed. If the
177 * caller provides null, the Toast will not be shown.
178 * @param cr The ContentResolver being used to remove the bookmark.
179 * @param url URL of the website to be removed.
180 */
181 /* package */ static void removeFromBookmarks(Context context,
Andrei Popescuc9526192009-09-23 15:52:16 +0100182 ContentResolver cr, String url, String title) {
Leon Scrogginse372c022009-06-12 17:07:29 -0400183 Cursor cursor = cr.query(
184 Browser.BOOKMARKS_URI,
185 Browser.HISTORY_PROJECTION,
Andrei Popescuc9526192009-09-23 15:52:16 +0100186 "url = ? AND title = ?",
187 new String[] { url, title },
Leon Scrogginse372c022009-06-12 17:07:29 -0400188 null);
189 boolean first = cursor.moveToFirst();
190 // Should be in the database no matter what
191 if (!first) {
Andrei Popescuc9526192009-09-23 15:52:16 +0100192 throw new AssertionError("URL is not in the database! " + url + " " + title);
Leon Scrogginse372c022009-06-12 17:07:29 -0400193 }
194 // Remove from bookmarks
195 WebIconDatabase.getInstance().releaseIconForPageUrl(url);
196 Uri uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI,
197 cursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX));
198 int numVisits = cursor.getInt(
199 Browser.HISTORY_PROJECTION_VISITS_INDEX);
200 if (0 == numVisits) {
201 cr.delete(uri, null, null);
202 } else {
203 // It is no longer a bookmark, but it is still a visited
204 // site.
205 ContentValues values = new ContentValues();
206 values.put(Browser.BookmarkColumns.BOOKMARK, 0);
207 try {
208 cr.update(uri, values, null, null);
209 } catch (IllegalStateException e) {
210 Log.e("removeFromBookmarks", "no database!");
211 }
212 }
213 if (context != null) {
214 Toast.makeText(context, R.string.removed_from_bookmarks,
215 Toast.LENGTH_LONG).show();
216 }
217 cursor.deactivate();
218 }
Ben Murdochaac7aa62009-09-17 16:57:40 +0100219
220 private static byte[] bitmapToBytes(Bitmap bm) {
221 if (bm == null) {
222 return null;
223 }
224
225 final ByteArrayOutputStream os = new ByteArrayOutputStream();
226 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
227 return os.toByteArray();
228 }
Ben Murdochde353622009-10-12 10:29:00 +0100229
230 /* package */ static boolean urlHasAcceptableScheme(String url) {
231 if (url == null) {
232 return false;
233 }
234
235 for (int i = 0; i < acceptableBookmarkSchemes.length; i++) {
236 if (url.startsWith(acceptableBookmarkSchemes[i])) {
237 return true;
238 }
239 }
240 return false;
241 }
Ben Murdochaac7aa62009-09-17 16:57:40 +0100242}