summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/browser/AddBookmarkPage.java2
-rw-r--r--src/com/android/browser/Bookmarks.java10
-rw-r--r--src/com/android/browser/BrowserBackupAgent.java181
-rw-r--r--src/com/android/browser/BrowserProvider.java29
-rw-r--r--src/com/android/browser/HistoryItem.java2
5 files changed, 171 insertions, 53 deletions
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index e827a7e..191659a 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -142,7 +142,7 @@ public class AddBookmarkPage extends Activity {
setResult(RESULT_OK, (new Intent()).setAction(
getIntent().toString()).putExtras(mMap));
} else {
- Bookmarks.addBookmark(null, getContentResolver(), url, title);
+ Bookmarks.addBookmark(null, getContentResolver(), url, title, true);
setResult(RESULT_OK);
}
} catch (IllegalStateException e) {
diff --git a/src/com/android/browser/Bookmarks.java b/src/com/android/browser/Bookmarks.java
index 97e6b20..a3dc919 100644
--- a/src/com/android/browser/Bookmarks.java
+++ b/src/com/android/browser/Bookmarks.java
@@ -47,9 +47,13 @@ import java.util.Date;
* @param cr The ContentResolver being used to add the bookmark to the db.
* @param url URL of the website to be bookmarked.
* @param name Provided name for the bookmark.
+ * @param retainIcon Whether to retain the page's icon in the icon database.
+ * This will usually be <code>true</code> except when bookmarks are
+ * added by a settings restore agent.
*/
/* package */ static void addBookmark(Context context,
- ContentResolver cr, String url, String name) {
+ ContentResolver cr, String url, String name,
+ boolean retainIcon) {
// Want to append to the beginning of the list
long creationTime = new Date().getTime();
// First we check to see if the user has already visited this
@@ -137,7 +141,9 @@ import java.util.Date;
cr.insert(Browser.BOOKMARKS_URI, map);
}
}
- WebIconDatabase.getInstance().retainIconForPageUrl(url);
+ if (retainIcon) {
+ WebIconDatabase.getInstance().retainIconForPageUrl(url);
+ }
cursor.deactivate();
if (context != null) {
Toast.makeText(context, R.string.added_to_bookmarks,
diff --git a/src/com/android/browser/BrowserBackupAgent.java b/src/com/android/browser/BrowserBackupAgent.java
index 9e10370..c239b12 100644
--- a/src/com/android/browser/BrowserBackupAgent.java
+++ b/src/com/android/browser/BrowserBackupAgent.java
@@ -25,14 +25,16 @@ import android.database.Cursor;
import android.os.ParcelFileDescriptor;
import android.provider.Browser;
import android.provider.Browser.BookmarkColumns;
+import android.util.Log;
+import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-
+import java.util.ArrayList;
import java.util.zip.CRC32;
/**
@@ -40,9 +42,16 @@ import java.util.zip.CRC32;
* stored is the set of bookmarks. It's okay if I/O exceptions are thrown
* out of the agent; the calling code handles it and the backup operation
* simply fails.
+ *
+ * @hide
*/
public class BrowserBackupAgent extends BackupAgent {
+ static final String TAG = "BrowserBookmarkAgent";
+ static final boolean DEBUG = true;
+
static final String BOOKMARK_KEY = "_bookmarks_";
+ /** this version num MUST be incremented if the flattened-file schema ever changes */
+ static final int BACKUP_AGENT_VERSION = 0;
/**
* In order to determine whether the bookmark set has changed since the
@@ -51,6 +60,7 @@ public class BrowserBackupAgent extends BackupAgent {
*
* 1. the size of the flattened bookmark file
* 2. the CRC32 of that file
+ * 3. the agent version number [relevant following an OTA]
*
* After we flatten the bookmarks file here in onBackup, we compare its
* metrics with the values from the saved state. If they match, it means
@@ -63,6 +73,7 @@ public class BrowserBackupAgent extends BackupAgent {
ParcelFileDescriptor newState) throws IOException {
long savedFileSize = -1;
long savedCrc = -1;
+ int savedVersion = -1;
// Extract the previous bookmark file size & CRC from the saved state
DataInputStream in = new DataInputStream(
@@ -70,59 +81,28 @@ public class BrowserBackupAgent extends BackupAgent {
try {
savedFileSize = in.readLong();
savedCrc = in.readLong();
+ savedVersion = in.readInt();
} catch (EOFException e) {
// It means we had no previous state; that's fine
}
- // TODO: BUILD THE FLATTENED BOOKMARK FILE FROM THE DB (into tmpfile)
- File tmpfile = getFilesDir().createTempFile("bkp", null);
- CRC32 crc = new CRC32();
+ // Build a flattened representation of the bookmarks table
+ File tmpfile = File.createTempFile("bkp", null, getCacheDir());
try {
- Cursor cursor = getContentResolver().query(Browser.BOOKMARKS_URI,
- new String[] { BookmarkColumns.URL, BookmarkColumns.VISITS,
- BookmarkColumns.DATE, BookmarkColumns.CREATED,
- BookmarkColumns.TITLE },
- BookmarkColumns.BOOKMARK + " == 1 ", null, null);
- int count = cursor.getCount();
- FileOutputStream out = new FileOutputStream(tmpfile);
- for (int i = 0; i < count; i++) {
- StringBuilder sb = new StringBuilder();
- // URL
- sb.append("'");
- sb.append(cursor.getString(0));
- sb.append("','");
- // VISITS
- sb.append(cursor.getInt(1));
- sb.append("','");
- // DATE
- sb.append(cursor.getLong(2));
- sb.append("','");
- // CREATED
- sb.append(cursor.getLong(3));
- sb.append("','");
- // TITLE
- sb.append(cursor.getString(4));
- sb.append("'");
- out.write(sb.toString().getBytes());
-
- cursor.moveToNext();
- }
- out.close();
- /*
- android.util.Log.d("s", "backing up data" +
- getContentResolver().openFileDescriptor(Browser.BOOKMARKS_URI, "r").toString());
- */
- // NOTE: feed the flattened data through the crc engine on the fly
- // to save re-reading it later just to checksum it
-
- // Once the file is built, compare its metrics with the saved ones
- if ((crc.getValue() != savedCrc) || (tmpfile.length() != savedFileSize)) {
+ FileOutputStream outfstream = new FileOutputStream(tmpfile);
+ long newCrc = buildBookmarkFile(outfstream);
+ outfstream.close();
+
+ // Any changes since the last backup?
+ if ((savedVersion != BACKUP_AGENT_VERSION)
+ || (newCrc != savedCrc)
+ || (tmpfile.length() != savedFileSize)) {
// Different checksum or different size, so we need to back it up
copyFileToBackup(BOOKMARK_KEY, tmpfile, data);
}
- // Last, record the metrics of the bookmark file that we just stored
- writeBackupState(tmpfile.length(), crc.getValue(), newState);
+ // Record our backup state and we're done
+ writeBackupState(tmpfile.length(), newCrc, newState);
} finally {
// Make sure to tidy up when we're done
tmpfile.delete();
@@ -138,14 +118,60 @@ public class BrowserBackupAgent extends BackupAgent {
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
long crc = -1;
- File tmpfile = getFilesDir().createTempFile("rst", null);
+ File tmpfile = File.createTempFile("rst", null, getFilesDir());
try {
while (data.readNextHeader()) {
if (BOOKMARK_KEY.equals(data.getKey())) {
// Read the flattened bookmark data into a temp file
crc = copyBackupToFile(data, tmpfile, data.getDataSize());
- // TODO: READ THE FLAT BOOKMARKS FILE 'tmpfile' AND REBUILD THE DB TABLE
+ FileInputStream infstream = new FileInputStream(tmpfile);
+ DataInputStream in = new DataInputStream(infstream);
+
+ try {
+ int count = in.readInt();
+ ArrayList<Bookmark> bookmarks = new ArrayList<Bookmark>(count);
+
+ // Read all the bookmarks, then process later -- if we can't read
+ // all the data successfully, we don't touch the bookmarks table
+ for (int i = 0; i < count; i++) {
+ Bookmark mark = new Bookmark();
+ mark.url = in.readUTF();
+ mark.visits = in.readInt();
+ mark.date = in.readLong();
+ mark.created = in.readLong();
+ mark.title = in.readUTF();
+ bookmarks.add(mark);
+ }
+
+ // Okay, we have all the bookmarks -- now see if we need to add
+ // them to the browser's database
+ int N = bookmarks.size();
+ if (DEBUG) Log.v(TAG, "Restoring " + N + " bookmarks");
+ String[] urlCol = new String[] { BookmarkColumns.URL };
+ for (int i = 0; i < N; i++) {
+ Bookmark mark = bookmarks.get(i);
+
+ // Does this URL exist in the bookmark table?
+ Cursor cursor = getContentResolver().query(Browser.BOOKMARKS_URI,
+ urlCol, BookmarkColumns.URL + " == '" + mark.url + "' AND " +
+ BookmarkColumns.BOOKMARK + " == 1 ", null, null);
+ // if not, insert it
+ if (cursor.getCount() <= 0) {
+ Log.v(TAG, "Did not see url: " + mark.url);
+ // Right now we do not reconstruct the db entry in its
+ // entirety; we just add a new bookmark with the same data
+ Bookmarks.addBookmark(null, getContentResolver(),
+ mark.url, mark.title, false);
+ } else {
+ Log.v(TAG, "Skipping extant url: " + mark.url);
+ }
+ cursor.close();
+ }
+ } catch (IOException ioe) {
+ Log.w(TAG, "Bad backup data; not restoring");
+ crc = -1;
+ }
}
// Last, write the state we just restored from so we can discern
@@ -158,10 +184,67 @@ public class BrowserBackupAgent extends BackupAgent {
}
}
+ class Bookmark {
+ public String url;
+ public int visits;
+ public long date;
+ public long created;
+ public String title;
+ }
/*
* Utility functions
*/
+ // Flatten the bookmarks table into the given file, calculating its CRC in the process
+ private long buildBookmarkFile(FileOutputStream outfstream) throws IOException {
+ CRC32 crc = new CRC32();
+ ByteArrayOutputStream bufstream = new ByteArrayOutputStream(512);
+ DataOutputStream bout = new DataOutputStream(bufstream);
+
+ Cursor cursor = getContentResolver().query(Browser.BOOKMARKS_URI,
+ new String[] { BookmarkColumns.URL, BookmarkColumns.VISITS,
+ BookmarkColumns.DATE, BookmarkColumns.CREATED,
+ BookmarkColumns.TITLE },
+ BookmarkColumns.BOOKMARK + " == 1 ", null, null);
+
+ // The first thing in the file is the row count...
+ int count = cursor.getCount();
+ if (DEBUG) Log.v(TAG, "Backing up " + count + " bookmarks");
+ bout.writeInt(count);
+ byte[] record = bufstream.toByteArray();
+ crc.update(record);
+ outfstream.write(record);
+
+ // ... followed by the data for each row
+ for (int i = 0; i < count; i++) {
+ cursor.moveToNext();
+
+ String url = cursor.getString(0);
+ int visits = cursor.getInt(1);
+ long date = cursor.getLong(2);
+ long created = cursor.getLong(3);
+ String title = cursor.getString(4);
+
+ // construct the flattened record in a byte array
+ bufstream.reset();
+ bout.writeUTF(url);
+ bout.writeInt(visits);
+ bout.writeLong(date);
+ bout.writeLong(created);
+ bout.writeUTF(title);
+
+ // Update the CRC and write the record to the temp file
+ record = bufstream.toByteArray();
+ crc.update(record);
+ outfstream.write(record);
+
+ if (DEBUG) Log.v(TAG, " wrote url " + url);
+ }
+
+ cursor.close();
+ return crc.getValue();
+ }
+
// Write the file to backup as a single record under the given key
private void copyFileToBackup(String key, File file, BackupDataOutput data)
throws IOException {
@@ -187,13 +270,16 @@ public class BrowserBackupAgent extends BackupAgent {
final int CHUNK = 8192;
byte[] buf = new byte[CHUNK];
CRC32 crc = new CRC32();
+ FileOutputStream out = new FileOutputStream(file);
while (toRead > 0) {
int numRead = data.readEntityData(buf, 0, CHUNK);
crc.update(buf, 0, numRead);
+ out.write(buf, 0, numRead);
toRead -= numRead;
}
+ out.close();
return crc.getValue();
}
@@ -204,5 +290,6 @@ public class BrowserBackupAgent extends BackupAgent {
new FileOutputStream(stateFile.getFileDescriptor()));
out.writeLong(fileSize);
out.writeLong(crc);
+ out.writeInt(BACKUP_AGENT_VERSION);
}
}
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index 29c65e8..b74c9eb 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -19,6 +19,7 @@ package com.android.browser;
import com.google.android.providers.GoogleSettings.Partner;
import android.app.SearchManager;
+import android.backup.BackupManager;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentUris;
@@ -54,6 +55,7 @@ import java.util.regex.Pattern;
public class BrowserProvider extends ContentProvider {
private SQLiteOpenHelper mOpenHelper;
+ private BackupManager mBackupManager;
private static final String sDatabaseName = "browser.db";
private static final String TAG = "BrowserProvider";
private static final String ORDER_BY = "visits DESC, date DESC";
@@ -264,6 +266,7 @@ public class BrowserProvider extends ContentProvider {
public boolean onCreate() {
final Context context = getContext();
mOpenHelper = new DatabaseHelper(context);
+ mBackupManager = new BackupManager(context);
// we added "picasa web album" into default bookmarks for version 19.
// To avoid erasing the bookmark table, we added it explicitly for
// version 18 and 19 as in the other cases, we will erase the table.
@@ -736,6 +739,7 @@ public class BrowserProvider extends ContentProvider {
@Override
public Uri insert(Uri url, ContentValues initialValues) {
+ boolean isBookmarkTable = false;
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int match = URI_MATCHER.match(url);
@@ -749,6 +753,7 @@ public class BrowserProvider extends ContentProvider {
uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI,
rowID);
}
+ isBookmarkTable = true;
break;
}
@@ -771,6 +776,11 @@ public class BrowserProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URL");
}
getContext().getContentResolver().notifyChange(uri, null);
+
+ // back up the new bookmark set if we just inserted one
+ if (isBookmarkTable) {
+ mBackupManager.dataChanged();
+ }
return uri;
}
@@ -783,7 +793,10 @@ public class BrowserProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URL");
}
- if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) {
+ // need to know whether it's the bookmarks table for a couple fo reasons
+ boolean isBookmarkTable = (match == URI_MATCH_BOOKMARKS_ID);
+
+ if (isBookmarkTable || match == URI_MATCH_SEARCHES_ID) {
StringBuilder sb = new StringBuilder();
if (where != null && where.length() > 0) {
sb.append("( ");
@@ -797,6 +810,11 @@ public class BrowserProvider extends ContentProvider {
int count = db.delete(TABLE_NAMES[match % 10], where, whereArgs);
getContext().getContentResolver().notifyChange(url, null);
+
+ // back up the new bookmark set if we just deleted one
+ if (isBookmarkTable) {
+ mBackupManager.dataChanged();
+ }
return count;
}
@@ -810,7 +828,9 @@ public class BrowserProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URL");
}
- if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) {
+ boolean isBookmarkTable = (match == URI_MATCH_BOOKMARKS_ID);
+
+ if (isBookmarkTable || match == URI_MATCH_SEARCHES_ID) {
StringBuilder sb = new StringBuilder();
if (where != null && where.length() > 0) {
sb.append("( ");
@@ -824,6 +844,11 @@ public class BrowserProvider extends ContentProvider {
int ret = db.update(TABLE_NAMES[match % 10], values, where, whereArgs);
getContext().getContentResolver().notifyChange(url, null);
+
+ // back up the new bookmark set if we just changed one
+ if (isBookmarkTable) {
+ mBackupManager.dataChanged();
+ }
return ret;
}
diff --git a/src/com/android/browser/HistoryItem.java b/src/com/android/browser/HistoryItem.java
index b37a3bd..8a994f3 100644
--- a/src/com/android/browser/HistoryItem.java
+++ b/src/com/android/browser/HistoryItem.java
@@ -46,7 +46,7 @@ import android.widget.TextView;
boolean isChecked) {
if (isChecked) {
Bookmarks.addBookmark(mContext,
- mContext.getContentResolver(), mUrl, getName());
+ mContext.getContentResolver(), mUrl, getName(), true);
} else {
Bookmarks.removeFromBookmarks(mContext,
mContext.getContentResolver(), mUrl);