/*
* Zirco Browser for Android
*
* Copyright (C) 2010 - 2011 J. Devauchelle and contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 3 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package org.gaeproxy.zirco.providers;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.gaeproxy.zirco.model.UrlSuggestionItemComparator;
import org.gaeproxy.zirco.model.adapters.UrlSuggestionCursorAdapter;
import org.gaeproxy.zirco.model.items.BookmarkItem;
import org.gaeproxy.zirco.model.items.HistoryItem;
import org.gaeproxy.zirco.model.items.UrlSuggestionItem;
import org.gaeproxy.zirco.model.items.WeaveBookmarkItem;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.Browser;
import android.util.Log;
public class BookmarksProviderWrapper {
private static String[] sHistoryBookmarksProjection = new String[] {
Browser.BookmarkColumns._ID, Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL, Browser.BookmarkColumns.VISITS,
Browser.BookmarkColumns.DATE, Browser.BookmarkColumns.CREATED,
Browser.BookmarkColumns.BOOKMARK, Browser.BookmarkColumns.FAVICON };
/**
* Clear the history/bookmarks table.
*
* @param contentResolver
* The content resolver.
* @param clearHistory
* If true, history items will be cleared.
* @param clearBookmarks
* If true, bookmarked items will be cleared.
*/
public static void clearHistoryAndOrBookmarks(
ContentResolver contentResolver, boolean clearHistory,
boolean clearBookmarks) {
if (!clearHistory && !clearBookmarks) {
return;
}
String whereClause = null;
if (clearHistory && clearBookmarks) {
whereClause = null;
} else if (clearHistory) {
whereClause = "(" + Browser.BookmarkColumns.BOOKMARK + " = 0) OR ("
+ Browser.BookmarkColumns.BOOKMARK + " IS NULL)";
} else if (clearBookmarks) {
whereClause = Browser.BookmarkColumns.BOOKMARK + " = 1";
}
contentResolver.delete(Browser.BOOKMARKS_URI, whereClause, null);
}
public static void clearWeaveBookmarks(ContentResolver contentResolver) {
contentResolver.delete(WeaveColumns.CONTENT_URI, null, null);
}
/**
* Delete an history record, e.g. reset the visited count and visited date
* if its a bookmark, or delete it if not.
*
* @param contentResolver
* The content resolver.
* @param id
* The history id.
*/
public static void deleteHistoryRecord(ContentResolver contentResolver,
long id) {
String whereClause = BaseColumns._ID + " = " + id;
Cursor cursor = contentResolver.query(
android.provider.Browser.BOOKMARKS_URI,
sHistoryBookmarksProjection, whereClause, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
if (cursor.getInt(cursor
.getColumnIndex(Browser.BookmarkColumns.BOOKMARK)) == 1) {
// The record is a bookmark, so we cannot delete it.
// Instead, reset its visited count and last visited date.
ContentValues values = new ContentValues();
values.put(Browser.BookmarkColumns.VISITS, 0);
values.putNull(Browser.BookmarkColumns.DATE);
contentResolver.update(Browser.BOOKMARKS_URI, values,
whereClause, null);
} else {
// The record is not a bookmark, we can delete it.
contentResolver.delete(Browser.BOOKMARKS_URI, whereClause,
null);
}
}
cursor.close();
}
}
public static void deleteStockBookmark(ContentResolver contentResolver,
long id) {
String whereClause = BaseColumns._ID + " = " + id;
Cursor c = contentResolver.query(Browser.BOOKMARKS_URI,
sHistoryBookmarksProjection, whereClause, null, null);
if (c != null) {
if (c.moveToFirst()) {
if (c.getInt(c.getColumnIndex(Browser.BookmarkColumns.BOOKMARK)) == 1) {
if (c.getInt(c
.getColumnIndex(Browser.BookmarkColumns.VISITS)) > 0) {
// If this record has been visited, keep it in history,
// but remove its bookmark flag.
ContentValues values = new ContentValues();
values.put(Browser.BookmarkColumns.BOOKMARK, 0);
values.putNull(Browser.BookmarkColumns.CREATED);
contentResolver.update(Browser.BOOKMARKS_URI, values,
whereClause, null);
} else {
// never visited, it can be deleted.
contentResolver.delete(Browser.BOOKMARKS_URI,
whereClause, null);
}
}
}
c.close();
}
}
public static void deleteWeaveBookmarkByWeaveId(
ContentResolver contentResolver, String weaveId) {
String whereClause = WeaveColumns.WEAVE_BOOKMARKS_WEAVE_ID + " = \""
+ weaveId + "\"";
contentResolver.delete(WeaveColumns.CONTENT_URI, whereClause, null);
}
/**
* Stock History/Bookmarks management.
*/
/**
* Get a Cursor on the whole content of the history/bookmarks database.
*
* @param contentResolver
* The content resolver.
* @return A Cursor.
* @see Cursor
*/
public static Cursor getAllStockRecords(ContentResolver contentResolver) {
return contentResolver.query(Browser.BOOKMARKS_URI,
sHistoryBookmarksProjection, null, null, null);
}
public static BookmarkItem getStockBookmarkById(
ContentResolver contentResolver, long id) {
BookmarkItem result = null;
String whereClause = BaseColumns._ID + " = " + id;
Cursor c = contentResolver.query(Browser.BOOKMARKS_URI,
sHistoryBookmarksProjection, whereClause, null, null);
if (c != null) {
if (c.moveToFirst()) {
String title = c.getString(c
.getColumnIndex(Browser.BookmarkColumns.TITLE));
String url = c.getString(c
.getColumnIndex(Browser.BookmarkColumns.URL));
result = new BookmarkItem(title, url);
}
c.close();
}
return result;
}
public static Cursor getStockBookmarks(ContentResolver contentResolver,
int sortMode) {
String whereClause = Browser.BookmarkColumns.BOOKMARK + " = 1";
String orderClause;
switch (sortMode) {
case 0:
orderClause = Browser.BookmarkColumns.VISITS + " DESC, "
+ Browser.BookmarkColumns.TITLE + " COLLATE NOCASE";
break;
case 1:
orderClause = Browser.BookmarkColumns.TITLE + " COLLATE NOCASE";
break;
case 2:
orderClause = Browser.BookmarkColumns.CREATED + " DESC";
break;
default:
orderClause = Browser.BookmarkColumns.TITLE + " COLLATE NOCASE";
break;
}
return contentResolver.query(Browser.BOOKMARKS_URI,
sHistoryBookmarksProjection, whereClause, null, orderClause);
}
/**
* Get a list of most visited bookmarks items, limited in size.
*
* @param contentResolver
* The content resolver.
* @param limit
* The size limit.
* @return A list of BookmarkItem.
*/
public static List<BookmarkItem> getStockBookmarksWithLimit(
ContentResolver contentResolver, int limit) {
List<BookmarkItem> result = new ArrayList<BookmarkItem>();
String whereClause = Browser.BookmarkColumns.BOOKMARK + " = 1";
String orderClause = Browser.BookmarkColumns.VISITS + " DESC";
String[] colums = new String[] { BaseColumns._ID,
Browser.BookmarkColumns.TITLE, Browser.BookmarkColumns.URL,
Browser.BookmarkColumns.FAVICON };
Cursor cursor = contentResolver.query(
android.provider.Browser.BOOKMARKS_URI, colums, whereClause,
null, orderClause);
if (cursor != null) {
if (cursor.moveToFirst()) {
int columnTitle = cursor
.getColumnIndex(Browser.BookmarkColumns.TITLE);
int columnUrl = cursor
.getColumnIndex(Browser.BookmarkColumns.URL);
int count = 0;
while (!cursor.isAfterLast() && (count < limit)) {
BookmarkItem item = new BookmarkItem(
cursor.getString(columnTitle),
cursor.getString(columnUrl));
result.add(item);
count++;
cursor.moveToNext();
}
}
cursor.close();
}
return result;
}
public static Cursor getStockHistory(ContentResolver contentResolver) {
String whereClause = Browser.BookmarkColumns.VISITS + " > 0";
String orderClause = Browser.BookmarkColumns.DATE + " DESC";
return contentResolver.query(Browser.BOOKMARKS_URI,
Browser.HISTORY_PROJECTION, whereClause, null, orderClause);
}
/**
* Get a list of most recent history items, limited in size.
*
* @param contentResolver
* The content resolver.
* @param limit
* The size limit.
* @return A list of HistoryItem.
*/
public static List<HistoryItem> getStockHistoryWithLimit(
ContentResolver contentResolver, int limit) {
List<HistoryItem> result = new ArrayList<HistoryItem>();
String whereClause = Browser.BookmarkColumns.VISITS + " > 0";
String orderClause = Browser.BookmarkColumns.DATE + " DESC";
Cursor cursor = contentResolver.query(
android.provider.Browser.BOOKMARKS_URI,
Browser.HISTORY_PROJECTION, whereClause, null, orderClause);
if (cursor != null) {
if (cursor.moveToFirst()) {
int columnId = cursor.getColumnIndex(BaseColumns._ID);
int columnTitle = cursor
.getColumnIndex(Browser.BookmarkColumns.TITLE);
int columnUrl = cursor
.getColumnIndex(Browser.BookmarkColumns.URL);
int count = 0;
while (!cursor.isAfterLast() && (count < limit)) {
HistoryItem item = new HistoryItem(
cursor.getLong(columnId),
cursor.getString(columnTitle),
cursor.getString(columnUrl), null);
result.add(item);
count++;
cursor.moveToNext();
}
}
cursor.close();
}
return result;
}
/**
* Suggestions.
*/
/**
* Get a cursor for suggestions, given a search pattern. Search on history
* and bookmarks, on title and url. The result list is sorted based on each
* result note.
*
* @see UrlSuggestionItem for how a note is computed.
* @param contentResolver
* The content resolver.
* @param pattern
* The pattern to search for.
* @param lookInWeaveBookmarks
* If true, suggestions will include bookmarks from weave.
* @return A cursor of suggections.
*/
public static Cursor getUrlSuggestions(ContentResolver contentResolver,
String pattern, boolean lookInWeaveBookmarks) {
MatrixCursor cursor = new MatrixCursor(new String[] {
UrlSuggestionCursorAdapter.URL_SUGGESTION_ID,
UrlSuggestionCursorAdapter.URL_SUGGESTION_TITLE,
UrlSuggestionCursorAdapter.URL_SUGGESTION_URL,
UrlSuggestionCursorAdapter.URL_SUGGESTION_TYPE });
if ((pattern != null) && (pattern.length() > 0)) {
String sqlPattern = "%" + pattern + "%";
List<UrlSuggestionItem> results = new ArrayList<UrlSuggestionItem>();
Cursor stockCursor = contentResolver.query(Browser.BOOKMARKS_URI,
sHistoryBookmarksProjection, Browser.BookmarkColumns.TITLE
+ " LIKE '" + sqlPattern + "' OR "
+ Browser.BookmarkColumns.URL + " LIKE '"
+ sqlPattern + "'", null, null);
if (stockCursor != null) {
if (stockCursor.moveToFirst()) {
int titleId = stockCursor
.getColumnIndex(Browser.BookmarkColumns.TITLE);
int urlId = stockCursor
.getColumnIndex(Browser.BookmarkColumns.URL);
int bookmarkId = stockCursor
.getColumnIndex(Browser.BookmarkColumns.BOOKMARK);
do {
boolean isFolder = stockCursor.getInt(bookmarkId) > 0 ? true
: false;
results.add(new UrlSuggestionItem(pattern, stockCursor
.getString(titleId), stockCursor
.getString(urlId), isFolder ? 2 : 1));
} while (stockCursor.moveToNext());
}
stockCursor.close();
}
if (lookInWeaveBookmarks) {
Cursor weaveCursor = contentResolver.query(
WeaveColumns.CONTENT_URI, null,
WeaveColumns.WEAVE_BOOKMARKS_FOLDER + " = 0 AND ("
+ WeaveColumns.WEAVE_BOOKMARKS_TITLE
+ " LIKE '" + sqlPattern + "' OR "
+ WeaveColumns.WEAVE_BOOKMARKS_URL + " LIKE '"
+ sqlPattern + "')", null, null);
if (weaveCursor != null) {
if (weaveCursor.moveToFirst()) {
int weaveTitleId = weaveCursor
.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_TITLE);
int weaveUrlId = weaveCursor
.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_URL);
do {
results.add(new UrlSuggestionItem(pattern,
weaveCursor.getString(weaveTitleId),
weaveCursor.getString(weaveUrlId), 3));
} while (weaveCursor.moveToNext());
}
weaveCursor.close();
}
}
// Sort results.
Collections.sort(results, new UrlSuggestionItemComparator());
// Log.d("Results", Integer.toString(results.size()));
// Copy results to the output MatrixCursor.
int idCounter = -1;
for (UrlSuggestionItem item : results) {
idCounter++;
String[] row = new String[4];
row[0] = Integer.toString(idCounter);
row[1] = item.getTitle();
row[2] = item.getUrl();
row[3] = Integer.toString(item.getType());
cursor.addRow(row);
}
}
return cursor;
}
public static WeaveBookmarkItem getWeaveBookmarkById(
ContentResolver contentResolver, long id) {
WeaveBookmarkItem result = null;
Uri uri = ContentUris.withAppendedId(WeaveColumns.CONTENT_URI, id);
Cursor c = contentResolver.query(uri, null, null, null, null);
if (c != null) {
if (c.moveToFirst()) {
String title = c.getString(c
.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_TITLE));
String url = c.getString(c
.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_URL));
String weaveId = c.getString(c
.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_WEAVE_ID));
boolean isFolder = c.getInt(c
.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_FOLDER)) > 0 ? true
: false;
result = new WeaveBookmarkItem(title, url, weaveId, isFolder);
}
c.close();
}
return result;
}
public static long getWeaveBookmarkIdByWeaveId(
ContentResolver contentResolver, String weaveId) {
long result = -1;
String whereClause = WeaveColumns.WEAVE_BOOKMARKS_WEAVE_ID + " = \""
+ weaveId + "\"";
Cursor c = contentResolver.query(WeaveColumns.CONTENT_URI, null,
whereClause, null, null);
if (c != null) {
if (c.moveToFirst()) {
result = c.getLong(c
.getColumnIndex(WeaveColumns.WEAVE_BOOKMARKS_ID));
}
c.close();
}
return result;
}
/**
* Weave bookmarks management.
*/
public static Cursor getWeaveBookmarksByParentId(
ContentResolver contentResolver, String parentId) {
String whereClause = WeaveColumns.WEAVE_BOOKMARKS_WEAVE_PARENT_ID
+ " = \"" + parentId + "\"";
String orderClause = WeaveColumns.WEAVE_BOOKMARKS_FOLDER + " DESC, "
+ WeaveColumns.WEAVE_BOOKMARKS_TITLE + " COLLATE NOCASE";
return contentResolver.query(WeaveColumns.CONTENT_URI,
WeaveColumns.WEAVE_BOOKMARKS_PROJECTION, whereClause, null,
orderClause);
}
/**
* Insert a full record in history/bookmarks database.
*
* @param contentResolver
* The content resolver.
* @param title
* The record title.
* @param url
* The record url.
* @param visits
* The record visit count.
* @param date
* The record last visit date.
* @param created
* The record bookmark creation date.
* @param bookmark
* The bookmark flag.
*/
public static void insertRawRecord(ContentResolver contentResolver,
String title, String url, int visits, long date, long created,
int bookmark) {
ContentValues values = new ContentValues();
values.put(Browser.BookmarkColumns.TITLE, title);
values.put(Browser.BookmarkColumns.URL, url);
values.put(Browser.BookmarkColumns.VISITS, visits);
if (date > 0) {
values.put(Browser.BookmarkColumns.DATE, date);
} else {
values.putNull(Browser.BookmarkColumns.DATE);
}
if (created > 0) {
values.put(Browser.BookmarkColumns.CREATED, created);
} else {
values.putNull(Browser.BookmarkColumns.CREATED);
}
if (bookmark > 0) {
values.put(Browser.BookmarkColumns.BOOKMARK, 1);
} else {
values.put(Browser.BookmarkColumns.BOOKMARK, 0);
}
contentResolver.insert(Browser.BOOKMARKS_URI, values);
}
public static void insertWeaveBookmark(ContentResolver contentResolver,
ContentValues values) {
contentResolver.insert(WeaveColumns.CONTENT_URI, values);
}
/**
* Modify a bookmark/history record. If an id is provided, it look for it
* and update its values. If not, values will be inserted. If no id is
* provided, it look for a record with the given url. It found, its values
* are updated. If not, values will be inserted.
*
* @param contentResolver
* The content resolver.
* @param id
* The record id to look for.
* @param title
* The record title.
* @param url
* The record url.
* @param isBookmark
* If True, the record will be a bookmark.
*/
public static void setAsBookmark(ContentResolver contentResolver, long id,
String title, String url, boolean isBookmark) {
boolean bookmarkExist = false;
if (id != -1) {
String[] colums = new String[] { BaseColumns._ID };
String whereClause = BaseColumns._ID + " = " + id;
Cursor cursor = contentResolver.query(
android.provider.Browser.BOOKMARKS_URI, colums,
whereClause, null, null);
bookmarkExist = (cursor != null) && (cursor.moveToFirst());
} else {
String[] colums = new String[] { BaseColumns._ID };
String whereClause = Browser.BookmarkColumns.URL + " = \"" + url
+ "\"";
Cursor cursor = contentResolver.query(
android.provider.Browser.BOOKMARKS_URI, colums,
whereClause, null, null);
bookmarkExist = (cursor != null) && (cursor.moveToFirst());
if (bookmarkExist) {
id = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
}
}
ContentValues values = new ContentValues();
if (title != null) {
values.put(Browser.BookmarkColumns.TITLE, title);
}
if (url != null) {
values.put(Browser.BookmarkColumns.URL, url);
}
if (isBookmark) {
values.put(Browser.BookmarkColumns.BOOKMARK, 1);
values.put(Browser.BookmarkColumns.CREATED, new Date().getTime());
} else {
values.put(Browser.BookmarkColumns.BOOKMARK, 0);
}
if (bookmarkExist) {
contentResolver.update(android.provider.Browser.BOOKMARKS_URI,
values, BaseColumns._ID + " = " + id, null);
} else {
contentResolver.insert(android.provider.Browser.BOOKMARKS_URI,
values);
}
}
/**
* Remove from history values prior to now minus the number of days defined
* in preferences. Only delete history items, not bookmarks.
*
* @param contentResolver
* The content resolver.
*/
public static void truncateHistory(ContentResolver contentResolver,
String prefHistorySize) {
int historySize;
try {
historySize = Integer.parseInt(prefHistorySize);
} catch (NumberFormatException e) {
historySize = 90;
}
Calendar c = Calendar.getInstance();
c.setTime(new Date());
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
c.add(Calendar.DAY_OF_YEAR, -historySize);
String whereClause = "(" + Browser.BookmarkColumns.BOOKMARK
+ " = 0 OR " + Browser.BookmarkColumns.BOOKMARK
+ " IS NULL) AND " + Browser.BookmarkColumns.DATE + " < "
+ c.getTimeInMillis();
try {
contentResolver.delete(Browser.BOOKMARKS_URI, whereClause, null);
} catch (Exception e) {
e.printStackTrace();
Log.w("BookmarksProviderWrapper", "Unable to truncate history: "
+ e.getMessage());
}
}
/**
* Update the favicon in history/bookmarks database.
*
* @param currentActivity
* The current acitivity.
* @param url
* The url.
* @param originalUrl
* The original url.
* @param favicon
* The favicon.
*/
public static void updateFavicon(Activity currentActivity, String url,
String originalUrl, Bitmap favicon) {
String whereClause;
if (!url.equals(originalUrl)) {
whereClause = Browser.BookmarkColumns.URL + " = \"" + url
+ "\" OR " + Browser.BookmarkColumns.URL + " = \""
+ originalUrl + "\"";
} else {
whereClause = Browser.BookmarkColumns.URL + " = \"" + url + "\"";
}
// BitmapDrawable icon =
// ApplicationUtils.getNormalizedFaviconForBookmarks(currentActivity,
// favicon);
BitmapDrawable icon = new BitmapDrawable(favicon);
ByteArrayOutputStream os = new ByteArrayOutputStream();
icon.getBitmap().compress(Bitmap.CompressFormat.PNG, 100, os);
ContentValues values = new ContentValues();
values.put(Browser.BookmarkColumns.FAVICON, os.toByteArray());
try {
currentActivity.getContentResolver().update(
android.provider.Browser.BOOKMARKS_URI, values,
whereClause, null);
} catch (Exception e) {
e.printStackTrace();
Log.w("BookmarksProviderWrapper",
"Unable to update favicon: " + e.getMessage());
}
}
/**
* Update the history: visit count and last visited date.
*
* @param contentResolver
* The content resolver.
* @param title
* The title.
* @param url
* The url.
* @param originalUrl
* The original url
*/
public static void updateHistory(ContentResolver contentResolver,
String title, String url, String originalUrl) {
String[] colums = new String[] { BaseColumns._ID,
Browser.BookmarkColumns.URL, Browser.BookmarkColumns.BOOKMARK,
Browser.BookmarkColumns.VISITS };
String whereClause = Browser.BookmarkColumns.URL + " = \"" + url
+ "\" OR " + Browser.BookmarkColumns.URL + " = \""
+ originalUrl + "\"";
Cursor cursor = contentResolver.query(Browser.BOOKMARKS_URI, colums,
whereClause, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
long id = cursor
.getLong(cursor.getColumnIndex(BaseColumns._ID));
int visits = cursor.getInt(cursor
.getColumnIndex(Browser.BookmarkColumns.VISITS)) + 1;
ContentValues values = new ContentValues();
// If its not a bookmark, we can update the title. If we were
// doing it on bookmarks, we would override the title choosen by
// the user.
if (cursor.getInt(cursor
.getColumnIndex(Browser.BookmarkColumns.BOOKMARK)) != 1) {
values.put(Browser.BookmarkColumns.TITLE, title);
}
values.put(Browser.BookmarkColumns.DATE, new Date().getTime());
values.put(Browser.BookmarkColumns.VISITS, visits);
contentResolver.update(android.provider.Browser.BOOKMARKS_URI,
values, BaseColumns._ID + " = " + id, null);
} else {
ContentValues values = new ContentValues();
values.put(Browser.BookmarkColumns.TITLE, title);
values.put(Browser.BookmarkColumns.URL, url);
values.put(Browser.BookmarkColumns.DATE, new Date().getTime());
values.put(Browser.BookmarkColumns.VISITS, 1);
values.put(Browser.BookmarkColumns.BOOKMARK, 0);
contentResolver.insert(android.provider.Browser.BOOKMARKS_URI,
values);
}
cursor.close();
}
}
public static void updateWeaveBookmark(ContentResolver contentResolver,
long id, ContentValues values) {
String whereClause = WeaveColumns.WEAVE_BOOKMARKS_ID + " = " + id;
contentResolver.update(WeaveColumns.CONTENT_URI, values, whereClause,
null);
}
}