blob: 4b74046333b889e6179677bedf1955a655ac6157 [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
Bijan Amirzada41242f22014-03-21 12:12:18 -070017package com.android.browser;
Leon Scrogginse372c022009-06-12 17:07:29 -040018
19import android.content.ContentResolver;
20import android.content.ContentUris;
21import android.content.ContentValues;
22import android.content.Context;
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050023import android.content.SharedPreferences;
Leon Scrogginse372c022009-06-12 17:07:29 -040024import android.database.Cursor;
Pankaj Garg6bedeba2015-06-23 15:47:37 -070025import android.database.sqlite.SQLiteException;
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;
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050029import android.preference.PreferenceManager;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080030
Bijan Amirzada41242f22014-03-21 12:12:18 -070031import com.android.browser.R;
32import com.android.browser.platformsupport.BrowserContract;
33import com.android.browser.platformsupport.BrowserContract.Combined;
34import com.android.browser.platformsupport.BrowserContract.Images;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080035
John Reck568467e2010-12-21 14:15:50 -080036import android.text.TextUtils;
Leon Scrogginse372c022009-06-12 17:07:29 -040037import android.util.Log;
Leon Scrogginse372c022009-06-12 17:07:29 -040038import android.widget.Toast;
39
Ben Murdochaac7aa62009-09-17 16:57:40 +010040import java.io.ByteArrayOutputStream;
Leon Scrogginse372c022009-06-12 17:07:29 -040041
42/**
43 * This class is purely to have a common place for adding/deleting bookmarks.
44 */
John Reck57928452011-02-17 12:44:07 -080045public class Bookmarks {
Ben Murdochde353622009-10-12 10:29:00 +010046
Leon Scroggins2c0f6112010-03-12 18:09:39 -050047 private final static String LOGTAG = "Bookmarks";
Leon Scrogginse372c022009-06-12 17:07:29 -040048 /**
49 * Add a bookmark to the database.
50 * @param context Context of the calling Activity. This is used to make
51 * Toast confirming that the bookmark has been added. If the
52 * caller provides null, the Toast will not be shown.
Leon Scrogginse372c022009-06-12 17:07:29 -040053 * @param url URL of the website to be bookmarked.
54 * @param name Provided name for the bookmark.
Ben Murdochaac7aa62009-09-17 16:57:40 +010055 * @param thumbnail A thumbnail for the bookmark.
Christopher Tate9c0dd8c2009-07-10 17:51:48 -070056 * @param retainIcon Whether to retain the page's icon in the icon database.
57 * This will usually be <code>true</code> except when bookmarks are
58 * added by a settings restore agent.
Leon Scroggins III052ce662010-09-13 14:44:16 -040059 * @param parent ID of the parent folder.
Leon Scrogginse372c022009-06-12 17:07:29 -040060 */
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050061 /* package */ static void addBookmark(Context context, boolean showToast, String url,
John Reckaf262e72011-07-25 13:55:44 -070062 String name, Bitmap thumbnail, long parent) {
Leon Scrogginse372c022009-06-12 17:07:29 -040063 // Want to append to the beginning of the list
Jeff Hamilton84029622010-08-05 14:29:28 -050064 ContentValues values = new ContentValues();
Leon Scroggins2c0f6112010-03-12 18:09:39 -050065 try {
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050066 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
Jeff Hamilton84029622010-08-05 14:29:28 -050067 values.put(BrowserContract.Bookmarks.TITLE, name);
68 values.put(BrowserContract.Bookmarks.URL, url);
69 values.put(BrowserContract.Bookmarks.IS_FOLDER, 0);
70 values.put(BrowserContract.Bookmarks.THUMBNAIL,
71 bitmapToBytes(thumbnail));
Leon Scroggins III052ce662010-09-13 14:44:16 -040072 values.put(BrowserContract.Bookmarks.PARENT, parent);
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050073 context.getContentResolver().insert(BrowserContract.Bookmarks.CONTENT_URI, values);
Leon Scroggins2c0f6112010-03-12 18:09:39 -050074 } catch (IllegalStateException e) {
75 Log.e(LOGTAG, "addBookmark", e);
Leon Scrogginse372c022009-06-12 17:07:29 -040076 }
Jeff Hamilton7f6cf3e2010-09-17 17:22:21 -050077 if (showToast) {
Leon Scrogginse372c022009-06-12 17:07:29 -040078 Toast.makeText(context, R.string.added_to_bookmarks,
79 Toast.LENGTH_LONG).show();
80 }
81 }
82
83 /**
84 * Remove a bookmark from the database. If the url is a visited site, it
85 * will remain in the database, but only as a history item, and not as a
86 * bookmarked site.
87 * @param context Context of the calling Activity. This is used to make
John Reck03b20542011-01-06 16:22:48 -080088 * Toast confirming that the bookmark has been removed and to
89 * lookup the correct content uri. It must not be null.
Leon Scrogginse372c022009-06-12 17:07:29 -040090 * @param cr The ContentResolver being used to remove the bookmark.
91 * @param url URL of the website to be removed.
92 */
93 /* package */ static void removeFromBookmarks(Context context,
Andrei Popescuc9526192009-09-23 15:52:16 +010094 ContentResolver cr, String url, String title) {
Leon Scroggins2c0f6112010-03-12 18:09:39 -050095 Cursor cursor = null;
96 try {
John Reck4b59db82010-11-16 15:40:34 -080097 Uri uri = BookmarkUtils.getBookmarksUri(context);
98 cursor = cr.query(uri,
Jeff Hamilton8ce956c2010-08-17 11:13:53 -050099 new String[] { BrowserContract.Bookmarks._ID },
100 BrowserContract.Bookmarks.URL + " = ? AND " +
101 BrowserContract.Bookmarks.TITLE + " = ?",
Leon Scroggins2c0f6112010-03-12 18:09:39 -0500102 new String[] { url, title },
103 null);
Jeff Hamilton8ce956c2010-08-17 11:13:53 -0500104
Jeff Hamilton8ce956c2010-08-17 11:13:53 -0500105 if (!cursor.moveToFirst()) {
John Reck4b59db82010-11-16 15:40:34 -0800106 return;
Leon Scrogginse372c022009-06-12 17:07:29 -0400107 }
Jeff Hamilton8ce956c2010-08-17 11:13:53 -0500108
Leon Scroggins2c0f6112010-03-12 18:09:39 -0500109 // Remove from bookmarks
John Reck4b59db82010-11-16 15:40:34 -0800110 uri = ContentUris.withAppendedId(BrowserContract.Bookmarks.CONTENT_URI,
Jeff Hamilton8ce956c2010-08-17 11:13:53 -0500111 cursor.getLong(0));
112 cr.delete(uri, null, null);
Leon Scroggins2c0f6112010-03-12 18:09:39 -0500113 if (context != null) {
John Reck03b20542011-01-06 16:22:48 -0800114 Toast.makeText(context, R.string.removed_from_bookmarks,
115 Toast.LENGTH_LONG).show();
Leon Scroggins2c0f6112010-03-12 18:09:39 -0500116 }
117 } catch (IllegalStateException e) {
118 Log.e(LOGTAG, "removeFromBookmarks", e);
119 } finally {
120 if (cursor != null) cursor.close();
Leon Scrogginse372c022009-06-12 17:07:29 -0400121 }
Leon Scrogginse372c022009-06-12 17:07:29 -0400122 }
Ben Murdochaac7aa62009-09-17 16:57:40 +0100123
124 private static byte[] bitmapToBytes(Bitmap bm) {
125 if (bm == null) {
126 return null;
127 }
128
129 final ByteArrayOutputStream os = new ByteArrayOutputStream();
130 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
131 return os.toByteArray();
132 }
Ben Murdochde353622009-10-12 10:29:00 +0100133
Jeff Hamilton8ce956c2010-08-17 11:13:53 -0500134 static final String QUERY_BOOKMARKS_WHERE =
Jeff Hamilton1a805652010-09-07 12:36:30 -0700135 Combined.URL + " == ? OR " +
John Reck57928452011-02-17 12:44:07 -0800136 Combined.URL + " == ?";
Jeff Hamilton8ce956c2010-08-17 11:13:53 -0500137
Pankaj Garg6bedeba2015-06-23 15:47:37 -0700138 private static String eatTrailingSlash(String input) {
139 if (TextUtils.isEmpty(input)) {
140 return input;
141 }
142
143 if (input.charAt(input.length() - 1) == '/') {
144 return input.substring(0, input.length() - 1);
145 }
146
147 return input;
148 }
149
John Reck57928452011-02-17 12:44:07 -0800150 public static Cursor queryCombinedForUrl(ContentResolver cr,
Jeff Hamilton8ce956c2010-08-17 11:13:53 -0500151 String originalUrl, String url) {
Jeff Hamilton84029622010-08-05 14:29:28 -0500152 if (cr == null || url == null) {
153 return null;
154 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800155
Jeff Hamilton84029622010-08-05 14:29:28 -0500156 // If originalUrl is null, just set it to url.
157 if (originalUrl == null) {
158 originalUrl = url;
159 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800160
Jeff Hamilton84029622010-08-05 14:29:28 -0500161 // Look for both the original url and the actual url. This takes in to
162 // account redirects.
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800163
John Reck57928452011-02-17 12:44:07 -0800164 final String[] selArgs = new String[] { originalUrl, url };
Jeff Hamilton1a805652010-09-07 12:36:30 -0700165 final String[] projection = new String[] { Combined.URL };
166 return cr.query(Combined.CONTENT_URI, projection, QUERY_BOOKMARKS_WHERE, selArgs, null);
Jeff Hamilton84029622010-08-05 14:29:28 -0500167 }
168
169 // Strip the query from the given url.
170 static String removeQuery(String url) {
171 if (url == null) {
172 return null;
173 }
174 int query = url.indexOf('?');
175 String noQuery = url;
176 if (query != -1) {
177 noQuery = url.substring(0, query);
178 }
179 return noQuery;
180 }
181
182 /**
183 * Update the bookmark's favicon. This is a convenience method for updating
184 * a bookmark favicon for the originalUrl and url of the passed in WebView.
185 * @param cr The ContentResolver to use.
186 * @param originalUrl The original url before any redirects.
187 * @param url The current url.
188 * @param favicon The favicon bitmap to write to the db.
189 */
Jeff Hamilton1a805652010-09-07 12:36:30 -0700190 /* package */ static void updateFavicon(final ContentResolver cr,
Jeff Hamilton84029622010-08-05 14:29:28 -0500191 final String originalUrl, final String url, final Bitmap favicon) {
192 new AsyncTask<Void, Void, Void>() {
193 @Override
194 protected Void doInBackground(Void... unused) {
John Reck568467e2010-12-21 14:15:50 -0800195 final ByteArrayOutputStream os = new ByteArrayOutputStream();
196 favicon.compress(Bitmap.CompressFormat.PNG, 100, os);
Pankaj Garg6bedeba2015-06-23 15:47:37 -0700197 byte[] image = os.toByteArray();
Jeff Hamilton1a805652010-09-07 12:36:30 -0700198
John Reck568467e2010-12-21 14:15:50 -0800199 // The Images update will insert if it doesn't exist
200 ContentValues values = new ContentValues();
Pankaj Garg6bedeba2015-06-23 15:47:37 -0700201 values.put(Images.FAVICON, image);
202 values.put(Images.THUMBNAIL, image);
203
204 updateImages(cr, removeQuery(originalUrl), values);
205 updateImages(cr, removeQuery(url), values);
206
207 Cursor cursor = null;
208 try {
209 cursor = queryCombinedForUrl(cr, originalUrl, url);
210 if (cursor != null && cursor.moveToFirst()) {
211 do {
212 updateImages(cr, cursor.getString(0), values);
213 } while (cursor.moveToNext());
214 }
Pankaj Garg68faf1c2015-06-26 17:07:37 -0700215
216 cursor = queryCombinedForUrl(cr, eatTrailingSlash(originalUrl),
217 eatTrailingSlash(url));
218 if (cursor != null && cursor.moveToFirst()) {
219 do {
220 updateImages(cr, cursor.getString(0), values);
221 } while (cursor.moveToNext());
222 }
Pankaj Garg6bedeba2015-06-23 15:47:37 -0700223 } catch (IllegalStateException e) {
224 // Ignore
225 } catch (SQLiteException s) {
226 // Ignore
227 } finally {
228 if (cursor != null) cursor.close();
229 }
230
Jeff Hamilton84029622010-08-05 14:29:28 -0500231 return null;
232 }
John Reck568467e2010-12-21 14:15:50 -0800233
234 private void updateImages(final ContentResolver cr,
Pankaj Garg6bedeba2015-06-23 15:47:37 -0700235 final String url, ContentValues values) {
236 if (!TextUtils.isEmpty(url)) {
237 values.put(Images.URL, url);
John Reck568467e2010-12-21 14:15:50 -0800238 cr.update(BrowserContract.Images.CONTENT_URI, values, null, null);
239 }
240 }
Jeff Hamilton84029622010-08-05 14:29:28 -0500241 }.execute();
242 }
Ben Murdochaac7aa62009-09-17 16:57:40 +0100243}