Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | package org.mozilla.gecko.db; |
michael@0 | 7 | |
michael@0 | 8 | import java.io.ByteArrayOutputStream; |
michael@0 | 9 | import java.io.File; |
michael@0 | 10 | import java.lang.reflect.Field; |
michael@0 | 11 | import java.util.ArrayList; |
michael@0 | 12 | import java.util.List; |
michael@0 | 13 | import java.util.Locale; |
michael@0 | 14 | import java.util.regex.Matcher; |
michael@0 | 15 | import java.util.regex.Pattern; |
michael@0 | 16 | |
michael@0 | 17 | import org.json.JSONArray; |
michael@0 | 18 | import org.json.JSONException; |
michael@0 | 19 | import org.json.JSONObject; |
michael@0 | 20 | import org.mozilla.gecko.AppConstants; |
michael@0 | 21 | import org.mozilla.gecko.Distribution; |
michael@0 | 22 | import org.mozilla.gecko.R; |
michael@0 | 23 | import org.mozilla.gecko.db.BrowserContract.Bookmarks; |
michael@0 | 24 | import org.mozilla.gecko.db.BrowserContract.Combined; |
michael@0 | 25 | import org.mozilla.gecko.db.BrowserContract.FaviconColumns; |
michael@0 | 26 | import org.mozilla.gecko.db.BrowserContract.Favicons; |
michael@0 | 27 | import org.mozilla.gecko.db.BrowserContract.History; |
michael@0 | 28 | import org.mozilla.gecko.db.BrowserContract.Obsolete; |
michael@0 | 29 | import org.mozilla.gecko.db.BrowserContract.ReadingListItems; |
michael@0 | 30 | import org.mozilla.gecko.db.BrowserContract.Thumbnails; |
michael@0 | 31 | import org.mozilla.gecko.gfx.BitmapUtils; |
michael@0 | 32 | import org.mozilla.gecko.sync.Utils; |
michael@0 | 33 | import org.mozilla.gecko.util.GeckoJarReader; |
michael@0 | 34 | import org.mozilla.gecko.util.ThreadUtils; |
michael@0 | 35 | |
michael@0 | 36 | import android.content.ContentValues; |
michael@0 | 37 | import android.content.Context; |
michael@0 | 38 | import android.database.Cursor; |
michael@0 | 39 | import android.database.DatabaseUtils; |
michael@0 | 40 | import android.database.SQLException; |
michael@0 | 41 | import android.database.sqlite.SQLiteDatabase; |
michael@0 | 42 | import android.database.sqlite.SQLiteOpenHelper; |
michael@0 | 43 | import android.graphics.Bitmap; |
michael@0 | 44 | import android.net.Uri; |
michael@0 | 45 | import android.os.Build; |
michael@0 | 46 | import android.text.TextUtils; |
michael@0 | 47 | import android.util.Log; |
michael@0 | 48 | |
michael@0 | 49 | |
michael@0 | 50 | final class BrowserDatabaseHelper extends SQLiteOpenHelper { |
michael@0 | 51 | |
michael@0 | 52 | private static final String LOGTAG = "GeckoBrowserDBHelper"; |
michael@0 | 53 | public static final int DATABASE_VERSION = 18; |
michael@0 | 54 | public static final String DATABASE_NAME = "browser.db"; |
michael@0 | 55 | |
michael@0 | 56 | final protected Context mContext; |
michael@0 | 57 | |
michael@0 | 58 | static final String TABLE_BOOKMARKS = Bookmarks.TABLE_NAME; |
michael@0 | 59 | static final String TABLE_HISTORY = History.TABLE_NAME; |
michael@0 | 60 | static final String TABLE_FAVICONS = Favicons.TABLE_NAME; |
michael@0 | 61 | static final String TABLE_THUMBNAILS = Thumbnails.TABLE_NAME; |
michael@0 | 62 | static final String TABLE_READING_LIST = ReadingListItems.TABLE_NAME; |
michael@0 | 63 | |
michael@0 | 64 | static final String VIEW_COMBINED = Combined.VIEW_NAME; |
michael@0 | 65 | static final String VIEW_BOOKMARKS_WITH_FAVICONS = Bookmarks.VIEW_WITH_FAVICONS; |
michael@0 | 66 | static final String VIEW_HISTORY_WITH_FAVICONS = History.VIEW_WITH_FAVICONS; |
michael@0 | 67 | static final String VIEW_COMBINED_WITH_FAVICONS = Combined.VIEW_WITH_FAVICONS; |
michael@0 | 68 | |
michael@0 | 69 | static final String TABLE_BOOKMARKS_JOIN_FAVICONS = TABLE_BOOKMARKS + " LEFT OUTER JOIN " + |
michael@0 | 70 | TABLE_FAVICONS + " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " = " + |
michael@0 | 71 | qualifyColumn(TABLE_FAVICONS, Favicons._ID); |
michael@0 | 72 | |
michael@0 | 73 | static final String TABLE_HISTORY_JOIN_FAVICONS = TABLE_HISTORY + " LEFT OUTER JOIN " + |
michael@0 | 74 | TABLE_FAVICONS + " ON " + qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " = " + |
michael@0 | 75 | qualifyColumn(TABLE_FAVICONS, Favicons._ID); |
michael@0 | 76 | |
michael@0 | 77 | static final String TABLE_BOOKMARKS_TMP = TABLE_BOOKMARKS + "_tmp"; |
michael@0 | 78 | static final String TABLE_HISTORY_TMP = TABLE_HISTORY + "_tmp"; |
michael@0 | 79 | static final String TABLE_IMAGES_TMP = Obsolete.TABLE_IMAGES + "_tmp"; |
michael@0 | 80 | |
michael@0 | 81 | private static final String[] mobileIdColumns = new String[] { Bookmarks._ID }; |
michael@0 | 82 | private static final String[] mobileIdSelectionArgs = new String[] { Bookmarks.MOBILE_FOLDER_GUID }; |
michael@0 | 83 | |
michael@0 | 84 | public BrowserDatabaseHelper(Context context, String databasePath) { |
michael@0 | 85 | super(context, databasePath, null, DATABASE_VERSION); |
michael@0 | 86 | mContext = context; |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | private void createBookmarksTable(SQLiteDatabase db) { |
michael@0 | 90 | debug("Creating " + TABLE_BOOKMARKS + " table"); |
michael@0 | 91 | |
michael@0 | 92 | // Android versions older than Froyo ship with an sqlite |
michael@0 | 93 | // that doesn't support foreign keys. |
michael@0 | 94 | String foreignKeyOnParent = null; |
michael@0 | 95 | if (Build.VERSION.SDK_INT >= 8) { |
michael@0 | 96 | foreignKeyOnParent = ", FOREIGN KEY (" + Bookmarks.PARENT + |
michael@0 | 97 | ") REFERENCES " + TABLE_BOOKMARKS + "(" + Bookmarks._ID + ")"; |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" + |
michael@0 | 101 | Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + |
michael@0 | 102 | Bookmarks.TITLE + " TEXT," + |
michael@0 | 103 | Bookmarks.URL + " TEXT," + |
michael@0 | 104 | Bookmarks.TYPE + " INTEGER NOT NULL DEFAULT " + Bookmarks.TYPE_BOOKMARK + "," + |
michael@0 | 105 | Bookmarks.PARENT + " INTEGER," + |
michael@0 | 106 | Bookmarks.POSITION + " INTEGER NOT NULL," + |
michael@0 | 107 | Bookmarks.KEYWORD + " TEXT," + |
michael@0 | 108 | Bookmarks.DESCRIPTION + " TEXT," + |
michael@0 | 109 | Bookmarks.TAGS + " TEXT," + |
michael@0 | 110 | Bookmarks.DATE_CREATED + " INTEGER," + |
michael@0 | 111 | Bookmarks.DATE_MODIFIED + " INTEGER," + |
michael@0 | 112 | Bookmarks.GUID + " TEXT NOT NULL," + |
michael@0 | 113 | Bookmarks.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" + |
michael@0 | 114 | (foreignKeyOnParent != null ? foreignKeyOnParent : "") + |
michael@0 | 115 | ");"); |
michael@0 | 116 | |
michael@0 | 117 | db.execSQL("CREATE INDEX bookmarks_url_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 118 | + Bookmarks.URL + ")"); |
michael@0 | 119 | db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 120 | + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")"); |
michael@0 | 121 | db.execSQL("CREATE UNIQUE INDEX bookmarks_guid_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 122 | + Bookmarks.GUID + ")"); |
michael@0 | 123 | db.execSQL("CREATE INDEX bookmarks_modified_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 124 | + Bookmarks.DATE_MODIFIED + ")"); |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | private void createBookmarksTableOn13(SQLiteDatabase db) { |
michael@0 | 128 | debug("Creating " + TABLE_BOOKMARKS + " table"); |
michael@0 | 129 | |
michael@0 | 130 | // Android versions older than Froyo ship with an sqlite |
michael@0 | 131 | // that doesn't support foreign keys. |
michael@0 | 132 | String foreignKeyOnParent = null; |
michael@0 | 133 | if (Build.VERSION.SDK_INT >= 8) { |
michael@0 | 134 | foreignKeyOnParent = ", FOREIGN KEY (" + Bookmarks.PARENT + |
michael@0 | 135 | ") REFERENCES " + TABLE_BOOKMARKS + "(" + Bookmarks._ID + ")"; |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | db.execSQL("CREATE TABLE " + TABLE_BOOKMARKS + "(" + |
michael@0 | 139 | Bookmarks._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + |
michael@0 | 140 | Bookmarks.TITLE + " TEXT," + |
michael@0 | 141 | Bookmarks.URL + " TEXT," + |
michael@0 | 142 | Bookmarks.TYPE + " INTEGER NOT NULL DEFAULT " + Bookmarks.TYPE_BOOKMARK + "," + |
michael@0 | 143 | Bookmarks.PARENT + " INTEGER," + |
michael@0 | 144 | Bookmarks.POSITION + " INTEGER NOT NULL," + |
michael@0 | 145 | Bookmarks.KEYWORD + " TEXT," + |
michael@0 | 146 | Bookmarks.DESCRIPTION + " TEXT," + |
michael@0 | 147 | Bookmarks.TAGS + " TEXT," + |
michael@0 | 148 | Bookmarks.FAVICON_ID + " INTEGER," + |
michael@0 | 149 | Bookmarks.DATE_CREATED + " INTEGER," + |
michael@0 | 150 | Bookmarks.DATE_MODIFIED + " INTEGER," + |
michael@0 | 151 | Bookmarks.GUID + " TEXT NOT NULL," + |
michael@0 | 152 | Bookmarks.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" + |
michael@0 | 153 | (foreignKeyOnParent != null ? foreignKeyOnParent : "") + |
michael@0 | 154 | ");"); |
michael@0 | 155 | |
michael@0 | 156 | db.execSQL("CREATE INDEX bookmarks_url_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 157 | + Bookmarks.URL + ")"); |
michael@0 | 158 | db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 159 | + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")"); |
michael@0 | 160 | db.execSQL("CREATE UNIQUE INDEX bookmarks_guid_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 161 | + Bookmarks.GUID + ")"); |
michael@0 | 162 | db.execSQL("CREATE INDEX bookmarks_modified_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 163 | + Bookmarks.DATE_MODIFIED + ")"); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | private void createHistoryTable(SQLiteDatabase db) { |
michael@0 | 167 | debug("Creating " + TABLE_HISTORY + " table"); |
michael@0 | 168 | db.execSQL("CREATE TABLE " + TABLE_HISTORY + "(" + |
michael@0 | 169 | History._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + |
michael@0 | 170 | History.TITLE + " TEXT," + |
michael@0 | 171 | History.URL + " TEXT NOT NULL," + |
michael@0 | 172 | History.VISITS + " INTEGER NOT NULL DEFAULT 0," + |
michael@0 | 173 | History.DATE_LAST_VISITED + " INTEGER," + |
michael@0 | 174 | History.DATE_CREATED + " INTEGER," + |
michael@0 | 175 | History.DATE_MODIFIED + " INTEGER," + |
michael@0 | 176 | History.GUID + " TEXT NOT NULL," + |
michael@0 | 177 | History.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" + |
michael@0 | 178 | ");"); |
michael@0 | 179 | |
michael@0 | 180 | db.execSQL("CREATE INDEX history_url_index ON " + TABLE_HISTORY + "(" |
michael@0 | 181 | + History.URL + ")"); |
michael@0 | 182 | db.execSQL("CREATE UNIQUE INDEX history_guid_index ON " + TABLE_HISTORY + "(" |
michael@0 | 183 | + History.GUID + ")"); |
michael@0 | 184 | db.execSQL("CREATE INDEX history_modified_index ON " + TABLE_HISTORY + "(" |
michael@0 | 185 | + History.DATE_MODIFIED + ")"); |
michael@0 | 186 | db.execSQL("CREATE INDEX history_visited_index ON " + TABLE_HISTORY + "(" |
michael@0 | 187 | + History.DATE_LAST_VISITED + ")"); |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | private void createHistoryTableOn13(SQLiteDatabase db) { |
michael@0 | 191 | debug("Creating " + TABLE_HISTORY + " table"); |
michael@0 | 192 | db.execSQL("CREATE TABLE " + TABLE_HISTORY + "(" + |
michael@0 | 193 | History._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + |
michael@0 | 194 | History.TITLE + " TEXT," + |
michael@0 | 195 | History.URL + " TEXT NOT NULL," + |
michael@0 | 196 | History.VISITS + " INTEGER NOT NULL DEFAULT 0," + |
michael@0 | 197 | History.FAVICON_ID + " INTEGER," + |
michael@0 | 198 | History.DATE_LAST_VISITED + " INTEGER," + |
michael@0 | 199 | History.DATE_CREATED + " INTEGER," + |
michael@0 | 200 | History.DATE_MODIFIED + " INTEGER," + |
michael@0 | 201 | History.GUID + " TEXT NOT NULL," + |
michael@0 | 202 | History.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" + |
michael@0 | 203 | ");"); |
michael@0 | 204 | |
michael@0 | 205 | db.execSQL("CREATE INDEX history_url_index ON " + TABLE_HISTORY + "(" |
michael@0 | 206 | + History.URL + ")"); |
michael@0 | 207 | db.execSQL("CREATE UNIQUE INDEX history_guid_index ON " + TABLE_HISTORY + "(" |
michael@0 | 208 | + History.GUID + ")"); |
michael@0 | 209 | db.execSQL("CREATE INDEX history_modified_index ON " + TABLE_HISTORY + "(" |
michael@0 | 210 | + History.DATE_MODIFIED + ")"); |
michael@0 | 211 | db.execSQL("CREATE INDEX history_visited_index ON " + TABLE_HISTORY + "(" |
michael@0 | 212 | + History.DATE_LAST_VISITED + ")"); |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | private void createImagesTable(SQLiteDatabase db) { |
michael@0 | 216 | debug("Creating " + Obsolete.TABLE_IMAGES + " table"); |
michael@0 | 217 | db.execSQL("CREATE TABLE " + Obsolete.TABLE_IMAGES + " (" + |
michael@0 | 218 | Obsolete.Images._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + |
michael@0 | 219 | Obsolete.Images.URL + " TEXT UNIQUE NOT NULL," + |
michael@0 | 220 | Obsolete.Images.FAVICON + " BLOB," + |
michael@0 | 221 | Obsolete.Images.FAVICON_URL + " TEXT," + |
michael@0 | 222 | Obsolete.Images.THUMBNAIL + " BLOB," + |
michael@0 | 223 | Obsolete.Images.DATE_CREATED + " INTEGER," + |
michael@0 | 224 | Obsolete.Images.DATE_MODIFIED + " INTEGER," + |
michael@0 | 225 | Obsolete.Images.GUID + " TEXT NOT NULL," + |
michael@0 | 226 | Obsolete.Images.IS_DELETED + " INTEGER NOT NULL DEFAULT 0" + |
michael@0 | 227 | ");"); |
michael@0 | 228 | |
michael@0 | 229 | db.execSQL("CREATE INDEX images_url_index ON " + Obsolete.TABLE_IMAGES + "(" |
michael@0 | 230 | + Obsolete.Images.URL + ")"); |
michael@0 | 231 | db.execSQL("CREATE UNIQUE INDEX images_guid_index ON " + Obsolete.TABLE_IMAGES + "(" |
michael@0 | 232 | + Obsolete.Images.GUID + ")"); |
michael@0 | 233 | db.execSQL("CREATE INDEX images_modified_index ON " + Obsolete.TABLE_IMAGES + "(" |
michael@0 | 234 | + Obsolete.Images.DATE_MODIFIED + ")"); |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | private void createFaviconsTable(SQLiteDatabase db) { |
michael@0 | 238 | debug("Creating " + TABLE_FAVICONS + " table"); |
michael@0 | 239 | db.execSQL("CREATE TABLE " + TABLE_FAVICONS + " (" + |
michael@0 | 240 | Favicons._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + |
michael@0 | 241 | Favicons.URL + " TEXT UNIQUE," + |
michael@0 | 242 | Favicons.DATA + " BLOB," + |
michael@0 | 243 | Favicons.DATE_CREATED + " INTEGER," + |
michael@0 | 244 | Favicons.DATE_MODIFIED + " INTEGER" + |
michael@0 | 245 | ");"); |
michael@0 | 246 | |
michael@0 | 247 | db.execSQL("CREATE INDEX favicons_url_index ON " + TABLE_FAVICONS + "(" |
michael@0 | 248 | + Favicons.URL + ")"); |
michael@0 | 249 | db.execSQL("CREATE INDEX favicons_modified_index ON " + TABLE_FAVICONS + "(" |
michael@0 | 250 | + Favicons.DATE_MODIFIED + ")"); |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | private void createThumbnailsTable(SQLiteDatabase db) { |
michael@0 | 254 | debug("Creating " + TABLE_THUMBNAILS + " table"); |
michael@0 | 255 | db.execSQL("CREATE TABLE " + TABLE_THUMBNAILS + " (" + |
michael@0 | 256 | Thumbnails._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + |
michael@0 | 257 | Thumbnails.URL + " TEXT UNIQUE," + |
michael@0 | 258 | Thumbnails.DATA + " BLOB" + |
michael@0 | 259 | ");"); |
michael@0 | 260 | |
michael@0 | 261 | db.execSQL("CREATE INDEX thumbnails_url_index ON " + TABLE_THUMBNAILS + "(" |
michael@0 | 262 | + Thumbnails.URL + ")"); |
michael@0 | 263 | } |
michael@0 | 264 | |
michael@0 | 265 | private void createBookmarksWithImagesView(SQLiteDatabase db) { |
michael@0 | 266 | debug("Creating " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES + " view"); |
michael@0 | 267 | |
michael@0 | 268 | db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES + " AS " + |
michael@0 | 269 | "SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") + |
michael@0 | 270 | ", " + Obsolete.Images.FAVICON + ", " + Obsolete.Images.THUMBNAIL + " FROM " + |
michael@0 | 271 | Obsolete.TABLE_BOOKMARKS_JOIN_IMAGES); |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | private void createBookmarksWithFaviconsView(SQLiteDatabase db) { |
michael@0 | 275 | debug("Creating " + VIEW_BOOKMARKS_WITH_FAVICONS + " view"); |
michael@0 | 276 | |
michael@0 | 277 | db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_BOOKMARKS_WITH_FAVICONS + " AS " + |
michael@0 | 278 | "SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") + |
michael@0 | 279 | ", " + qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Bookmarks.FAVICON + |
michael@0 | 280 | ", " + qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Bookmarks.FAVICON_URL + |
michael@0 | 281 | " FROM " + TABLE_BOOKMARKS_JOIN_FAVICONS); |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | private void createHistoryWithImagesView(SQLiteDatabase db) { |
michael@0 | 285 | debug("Creating " + Obsolete.VIEW_HISTORY_WITH_IMAGES + " view"); |
michael@0 | 286 | |
michael@0 | 287 | db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES + " AS " + |
michael@0 | 288 | "SELECT " + qualifyColumn(TABLE_HISTORY, "*") + |
michael@0 | 289 | ", " + Obsolete.Images.FAVICON + ", " + Obsolete.Images.THUMBNAIL + " FROM " + |
michael@0 | 290 | Obsolete.TABLE_HISTORY_JOIN_IMAGES); |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | private void createHistoryWithFaviconsView(SQLiteDatabase db) { |
michael@0 | 294 | debug("Creating " + VIEW_HISTORY_WITH_FAVICONS + " view"); |
michael@0 | 295 | |
michael@0 | 296 | db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_HISTORY_WITH_FAVICONS + " AS " + |
michael@0 | 297 | "SELECT " + qualifyColumn(TABLE_HISTORY, "*") + |
michael@0 | 298 | ", " + qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + History.FAVICON + |
michael@0 | 299 | ", " + qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + History.FAVICON_URL + |
michael@0 | 300 | " FROM " + TABLE_HISTORY_JOIN_FAVICONS); |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | private void createCombinedWithImagesView(SQLiteDatabase db) { |
michael@0 | 304 | debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view"); |
michael@0 | 305 | |
michael@0 | 306 | db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" + |
michael@0 | 307 | " SELECT " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 308 | Combined.HISTORY_ID + ", " + |
michael@0 | 309 | // We need to return an _id column because CursorAdapter requires it for its |
michael@0 | 310 | // default implementation for the getItemId() method. However, since |
michael@0 | 311 | // we're not using this feature in the parts of the UI using this view, |
michael@0 | 312 | // we can just use 0 for all rows. |
michael@0 | 313 | "0 AS " + Combined._ID + ", " + |
michael@0 | 314 | Combined.URL + ", " + |
michael@0 | 315 | Combined.TITLE + ", " + |
michael@0 | 316 | Combined.VISITS + ", " + |
michael@0 | 317 | Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 318 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " + |
michael@0 | 319 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL + |
michael@0 | 320 | " FROM (" + |
michael@0 | 321 | // Bookmarks without history. |
michael@0 | 322 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 323 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 324 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " + |
michael@0 | 325 | "-1 AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 326 | "-1 AS " + Combined.VISITS + ", " + |
michael@0 | 327 | "-1 AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 328 | " FROM " + TABLE_BOOKMARKS + |
michael@0 | 329 | " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " + |
michael@0 | 330 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " + |
michael@0 | 331 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + |
michael@0 | 332 | " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" + |
michael@0 | 333 | " UNION ALL" + |
michael@0 | 334 | // History with and without bookmark. |
michael@0 | 335 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 336 | qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 337 | // Prioritze bookmark titles over history titles, since the user may have |
michael@0 | 338 | // customized the title for a bookmark. |
michael@0 | 339 | "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " + |
michael@0 | 340 | qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " + |
michael@0 | 341 | qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 342 | qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " + |
michael@0 | 343 | qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 344 | " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS + |
michael@0 | 345 | " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) + |
michael@0 | 346 | " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " + |
michael@0 | 347 | qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" + |
michael@0 | 348 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " + |
michael@0 | 349 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ")" + |
michael@0 | 350 | ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES + |
michael@0 | 351 | " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL)); |
michael@0 | 352 | } |
michael@0 | 353 | |
michael@0 | 354 | private void createCombinedWithImagesViewOn9(SQLiteDatabase db) { |
michael@0 | 355 | debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view"); |
michael@0 | 356 | |
michael@0 | 357 | db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" + |
michael@0 | 358 | " SELECT " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 359 | Combined.HISTORY_ID + ", " + |
michael@0 | 360 | // We need to return an _id column because CursorAdapter requires it for its |
michael@0 | 361 | // default implementation for the getItemId() method. However, since |
michael@0 | 362 | // we're not using this feature in the parts of the UI using this view, |
michael@0 | 363 | // we can just use 0 for all rows. |
michael@0 | 364 | "0 AS " + Combined._ID + ", " + |
michael@0 | 365 | Combined.URL + ", " + |
michael@0 | 366 | Combined.TITLE + ", " + |
michael@0 | 367 | Combined.VISITS + ", " + |
michael@0 | 368 | Combined.DISPLAY + ", " + |
michael@0 | 369 | Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 370 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " + |
michael@0 | 371 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL + |
michael@0 | 372 | " FROM (" + |
michael@0 | 373 | // Bookmarks without history. |
michael@0 | 374 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 375 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 376 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " + |
michael@0 | 377 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 378 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 379 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 380 | "-1 AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 381 | "-1 AS " + Combined.VISITS + ", " + |
michael@0 | 382 | "-1 AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 383 | " FROM " + TABLE_BOOKMARKS + |
michael@0 | 384 | " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " + |
michael@0 | 385 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " + |
michael@0 | 386 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + |
michael@0 | 387 | " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" + |
michael@0 | 388 | " UNION ALL" + |
michael@0 | 389 | // History with and without bookmark. |
michael@0 | 390 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 391 | qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 392 | // Prioritze bookmark titles over history titles, since the user may have |
michael@0 | 393 | // customized the title for a bookmark. |
michael@0 | 394 | "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " + |
michael@0 | 395 | qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " + |
michael@0 | 396 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 397 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 398 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 399 | qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 400 | qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " + |
michael@0 | 401 | qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 402 | " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS + |
michael@0 | 403 | " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) + |
michael@0 | 404 | " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " + |
michael@0 | 405 | qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" + |
michael@0 | 406 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " + |
michael@0 | 407 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ")" + |
michael@0 | 408 | ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES + |
michael@0 | 409 | " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL)); |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | private void createCombinedWithImagesViewOn10(SQLiteDatabase db) { |
michael@0 | 413 | debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view"); |
michael@0 | 414 | |
michael@0 | 415 | db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" + |
michael@0 | 416 | " SELECT " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 417 | Combined.HISTORY_ID + ", " + |
michael@0 | 418 | // We need to return an _id column because CursorAdapter requires it for its |
michael@0 | 419 | // default implementation for the getItemId() method. However, since |
michael@0 | 420 | // we're not using this feature in the parts of the UI using this view, |
michael@0 | 421 | // we can just use 0 for all rows. |
michael@0 | 422 | "0 AS " + Combined._ID + ", " + |
michael@0 | 423 | Combined.URL + ", " + |
michael@0 | 424 | Combined.TITLE + ", " + |
michael@0 | 425 | Combined.VISITS + ", " + |
michael@0 | 426 | Combined.DISPLAY + ", " + |
michael@0 | 427 | Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 428 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " + |
michael@0 | 429 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL + |
michael@0 | 430 | " FROM (" + |
michael@0 | 431 | // Bookmarks without history. |
michael@0 | 432 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 433 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 434 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " + |
michael@0 | 435 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 436 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 437 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 438 | "-1 AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 439 | "-1 AS " + Combined.VISITS + ", " + |
michael@0 | 440 | "-1 AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 441 | " FROM " + TABLE_BOOKMARKS + |
michael@0 | 442 | " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " + |
michael@0 | 443 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " + |
michael@0 | 444 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + |
michael@0 | 445 | " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" + |
michael@0 | 446 | " UNION ALL" + |
michael@0 | 447 | // History with and without bookmark. |
michael@0 | 448 | " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " + |
michael@0 | 449 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 450 | qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 451 | // Prioritze bookmark titles over history titles, since the user may have |
michael@0 | 452 | // customized the title for a bookmark. |
michael@0 | 453 | "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " + |
michael@0 | 454 | qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " + |
michael@0 | 455 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 456 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 457 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 458 | qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 459 | qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " + |
michael@0 | 460 | qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 461 | " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS + |
michael@0 | 462 | " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) + |
michael@0 | 463 | " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " + |
michael@0 | 464 | qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" + |
michael@0 | 465 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " + |
michael@0 | 466 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ")" + |
michael@0 | 467 | ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES + |
michael@0 | 468 | " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL)); |
michael@0 | 469 | } |
michael@0 | 470 | |
michael@0 | 471 | private void createCombinedWithImagesViewOn11(SQLiteDatabase db) { |
michael@0 | 472 | debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view"); |
michael@0 | 473 | |
michael@0 | 474 | db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" + |
michael@0 | 475 | " SELECT " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 476 | Combined.HISTORY_ID + ", " + |
michael@0 | 477 | // We need to return an _id column because CursorAdapter requires it for its |
michael@0 | 478 | // default implementation for the getItemId() method. However, since |
michael@0 | 479 | // we're not using this feature in the parts of the UI using this view, |
michael@0 | 480 | // we can just use 0 for all rows. |
michael@0 | 481 | "0 AS " + Combined._ID + ", " + |
michael@0 | 482 | Combined.URL + ", " + |
michael@0 | 483 | Combined.TITLE + ", " + |
michael@0 | 484 | Combined.VISITS + ", " + |
michael@0 | 485 | Combined.DISPLAY + ", " + |
michael@0 | 486 | Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 487 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " + |
michael@0 | 488 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL + |
michael@0 | 489 | " FROM (" + |
michael@0 | 490 | // Bookmarks without history. |
michael@0 | 491 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 492 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 493 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " + |
michael@0 | 494 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 495 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 496 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 497 | "-1 AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 498 | "-1 AS " + Combined.VISITS + ", " + |
michael@0 | 499 | "-1 AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 500 | " FROM " + TABLE_BOOKMARKS + |
michael@0 | 501 | " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " + |
michael@0 | 502 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " + |
michael@0 | 503 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + |
michael@0 | 504 | " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" + |
michael@0 | 505 | " UNION ALL" + |
michael@0 | 506 | // History with and without bookmark. |
michael@0 | 507 | " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " + |
michael@0 | 508 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 509 | qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 510 | // Prioritze bookmark titles over history titles, since the user may have |
michael@0 | 511 | // customized the title for a bookmark. |
michael@0 | 512 | "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " + |
michael@0 | 513 | qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " + |
michael@0 | 514 | // Only use DISPLAY_READER if the matching bookmark entry inside reading |
michael@0 | 515 | // list folder is not marked as deleted. |
michael@0 | 516 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " + |
michael@0 | 517 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID + |
michael@0 | 518 | " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " + |
michael@0 | 519 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 520 | qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 521 | qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " + |
michael@0 | 522 | qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 523 | " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS + |
michael@0 | 524 | " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) + |
michael@0 | 525 | " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " + |
michael@0 | 526 | qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" + |
michael@0 | 527 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " + |
michael@0 | 528 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ") " + |
michael@0 | 529 | ") LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES + |
michael@0 | 530 | " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL)); |
michael@0 | 531 | } |
michael@0 | 532 | |
michael@0 | 533 | private void createCombinedViewOn12(SQLiteDatabase db) { |
michael@0 | 534 | debug("Creating " + VIEW_COMBINED + " view"); |
michael@0 | 535 | |
michael@0 | 536 | db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" + |
michael@0 | 537 | " SELECT " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 538 | Combined.HISTORY_ID + ", " + |
michael@0 | 539 | // We need to return an _id column because CursorAdapter requires it for its |
michael@0 | 540 | // default implementation for the getItemId() method. However, since |
michael@0 | 541 | // we're not using this feature in the parts of the UI using this view, |
michael@0 | 542 | // we can just use 0 for all rows. |
michael@0 | 543 | "0 AS " + Combined._ID + ", " + |
michael@0 | 544 | Combined.URL + ", " + |
michael@0 | 545 | Combined.TITLE + ", " + |
michael@0 | 546 | Combined.VISITS + ", " + |
michael@0 | 547 | Combined.DISPLAY + ", " + |
michael@0 | 548 | Combined.DATE_LAST_VISITED + |
michael@0 | 549 | " FROM (" + |
michael@0 | 550 | // Bookmarks without history. |
michael@0 | 551 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 552 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 553 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " + |
michael@0 | 554 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 555 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 556 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 557 | "-1 AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 558 | "-1 AS " + Combined.VISITS + ", " + |
michael@0 | 559 | "-1 AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 560 | " FROM " + TABLE_BOOKMARKS + |
michael@0 | 561 | " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " + |
michael@0 | 562 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " + |
michael@0 | 563 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + |
michael@0 | 564 | " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" + |
michael@0 | 565 | " UNION ALL" + |
michael@0 | 566 | // History with and without bookmark. |
michael@0 | 567 | " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " + |
michael@0 | 568 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 569 | qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 570 | // Prioritze bookmark titles over history titles, since the user may have |
michael@0 | 571 | // customized the title for a bookmark. |
michael@0 | 572 | "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " + |
michael@0 | 573 | qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " + |
michael@0 | 574 | // Only use DISPLAY_READER if the matching bookmark entry inside reading |
michael@0 | 575 | // list folder is not marked as deleted. |
michael@0 | 576 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " + |
michael@0 | 577 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID + |
michael@0 | 578 | " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " + |
michael@0 | 579 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 580 | qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 581 | qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " + |
michael@0 | 582 | qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + |
michael@0 | 583 | " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS + |
michael@0 | 584 | " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) + |
michael@0 | 585 | " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " + |
michael@0 | 586 | qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" + |
michael@0 | 587 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " + |
michael@0 | 588 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ") " + |
michael@0 | 589 | ")"); |
michael@0 | 590 | |
michael@0 | 591 | debug("Creating " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " view"); |
michael@0 | 592 | |
michael@0 | 593 | db.execSQL("CREATE VIEW IF NOT EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES + " AS" + |
michael@0 | 594 | " SELECT *, " + |
michael@0 | 595 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.FAVICON) + " AS " + Combined.FAVICON + ", " + |
michael@0 | 596 | qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.THUMBNAIL) + " AS " + Obsolete.Combined.THUMBNAIL + |
michael@0 | 597 | " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + Obsolete.TABLE_IMAGES + |
michael@0 | 598 | " ON " + Combined.URL + " = " + qualifyColumn(Obsolete.TABLE_IMAGES, Obsolete.Images.URL)); |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | private void createCombinedViewOn13(SQLiteDatabase db) { |
michael@0 | 602 | debug("Creating " + VIEW_COMBINED + " view"); |
michael@0 | 603 | |
michael@0 | 604 | db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" + |
michael@0 | 605 | " SELECT " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 606 | Combined.HISTORY_ID + ", " + |
michael@0 | 607 | // We need to return an _id column because CursorAdapter requires it for its |
michael@0 | 608 | // default implementation for the getItemId() method. However, since |
michael@0 | 609 | // we're not using this feature in the parts of the UI using this view, |
michael@0 | 610 | // we can just use 0 for all rows. |
michael@0 | 611 | "0 AS " + Combined._ID + ", " + |
michael@0 | 612 | Combined.URL + ", " + |
michael@0 | 613 | Combined.TITLE + ", " + |
michael@0 | 614 | Combined.VISITS + ", " + |
michael@0 | 615 | Combined.DISPLAY + ", " + |
michael@0 | 616 | Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 617 | Combined.FAVICON_ID + |
michael@0 | 618 | " FROM (" + |
michael@0 | 619 | // Bookmarks without history. |
michael@0 | 620 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 621 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 622 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " + |
michael@0 | 623 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 624 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 625 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 626 | "-1 AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 627 | "-1 AS " + Combined.VISITS + ", " + |
michael@0 | 628 | "-1 AS " + Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 629 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " AS " + Combined.FAVICON_ID + |
michael@0 | 630 | " FROM " + TABLE_BOOKMARKS + |
michael@0 | 631 | " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " + |
michael@0 | 632 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " + |
michael@0 | 633 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + |
michael@0 | 634 | " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" + |
michael@0 | 635 | " UNION ALL" + |
michael@0 | 636 | // History with and without bookmark. |
michael@0 | 637 | " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " + |
michael@0 | 638 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 639 | qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 640 | // Prioritize bookmark titles over history titles, since the user may have |
michael@0 | 641 | // customized the title for a bookmark. |
michael@0 | 642 | "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " + |
michael@0 | 643 | qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " + |
michael@0 | 644 | // Only use DISPLAY_READER if the matching bookmark entry inside reading |
michael@0 | 645 | // list folder is not marked as deleted. |
michael@0 | 646 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " + |
michael@0 | 647 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID + |
michael@0 | 648 | " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " + |
michael@0 | 649 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 650 | qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 651 | qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " + |
michael@0 | 652 | qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 653 | qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " AS " + Combined.FAVICON_ID + |
michael@0 | 654 | " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS + |
michael@0 | 655 | " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) + |
michael@0 | 656 | " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " + |
michael@0 | 657 | qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" + |
michael@0 | 658 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " + |
michael@0 | 659 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ") " + |
michael@0 | 660 | ")"); |
michael@0 | 661 | |
michael@0 | 662 | debug("Creating " + VIEW_COMBINED_WITH_FAVICONS + " view"); |
michael@0 | 663 | |
michael@0 | 664 | db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED_WITH_FAVICONS + " AS" + |
michael@0 | 665 | " SELECT " + qualifyColumn(VIEW_COMBINED, "*") + ", " + |
michael@0 | 666 | qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Combined.FAVICON_URL + ", " + |
michael@0 | 667 | qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Combined.FAVICON + |
michael@0 | 668 | " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + TABLE_FAVICONS + |
michael@0 | 669 | " ON " + Combined.FAVICON_ID + " = " + qualifyColumn(TABLE_FAVICONS, Favicons._ID)); |
michael@0 | 670 | } |
michael@0 | 671 | |
michael@0 | 672 | private void createCombinedViewOn16(SQLiteDatabase db) { |
michael@0 | 673 | debug("Creating " + VIEW_COMBINED + " view"); |
michael@0 | 674 | |
michael@0 | 675 | db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" + |
michael@0 | 676 | " SELECT " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 677 | Combined.HISTORY_ID + ", " + |
michael@0 | 678 | // We need to return an _id column because CursorAdapter requires it for its |
michael@0 | 679 | // default implementation for the getItemId() method. However, since |
michael@0 | 680 | // we're not using this feature in the parts of the UI using this view, |
michael@0 | 681 | // we can just use 0 for all rows. |
michael@0 | 682 | "0 AS " + Combined._ID + ", " + |
michael@0 | 683 | Combined.URL + ", " + |
michael@0 | 684 | Combined.TITLE + ", " + |
michael@0 | 685 | Combined.VISITS + ", " + |
michael@0 | 686 | Combined.DISPLAY + ", " + |
michael@0 | 687 | Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 688 | Combined.FAVICON_ID + |
michael@0 | 689 | " FROM (" + |
michael@0 | 690 | // Bookmarks without history. |
michael@0 | 691 | " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 692 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 693 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " + |
michael@0 | 694 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 695 | Bookmarks.FIXED_READING_LIST_ID + " THEN " + Combined.DISPLAY_READER + " ELSE " + |
michael@0 | 696 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 697 | "-1 AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 698 | "-1 AS " + Combined.VISITS + ", " + |
michael@0 | 699 | "-1 AS " + Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 700 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " AS " + Combined.FAVICON_ID + |
michael@0 | 701 | " FROM " + TABLE_BOOKMARKS + |
michael@0 | 702 | " WHERE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + " AND " + |
michael@0 | 703 | // Ignore pinned bookmarks. |
michael@0 | 704 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " <> " + Bookmarks.FIXED_PINNED_LIST_ID + " AND " + |
michael@0 | 705 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0 AND " + |
michael@0 | 706 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + |
michael@0 | 707 | " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" + |
michael@0 | 708 | " UNION ALL" + |
michael@0 | 709 | // History with and without bookmark. |
michael@0 | 710 | " SELECT " + "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN " + |
michael@0 | 711 | // Give pinned bookmarks a NULL ID so that they're not treated as bookmarks. We can't |
michael@0 | 712 | // completely ignore them here because they're joined with history entries we care about. |
michael@0 | 713 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + |
michael@0 | 714 | Bookmarks.FIXED_PINNED_LIST_ID + " THEN NULL ELSE " + |
michael@0 | 715 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " END " + |
michael@0 | 716 | "ELSE NULL END AS " + Combined.BOOKMARK_ID + ", " + |
michael@0 | 717 | qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + ", " + |
michael@0 | 718 | // Prioritize bookmark titles over history titles, since the user may have |
michael@0 | 719 | // customized the title for a bookmark. |
michael@0 | 720 | "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " + |
michael@0 | 721 | qualifyColumn(TABLE_HISTORY, History.TITLE) +")" + " AS " + Combined.TITLE + ", " + |
michael@0 | 722 | // Only use DISPLAY_READER if the matching bookmark entry inside reading |
michael@0 | 723 | // list folder is not marked as deleted. |
michael@0 | 724 | "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " WHEN 0 THEN CASE " + |
michael@0 | 725 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) + " WHEN " + Bookmarks.FIXED_READING_LIST_ID + |
michael@0 | 726 | " THEN " + Combined.DISPLAY_READER + " ELSE " + Combined.DISPLAY_NORMAL + " END ELSE " + |
michael@0 | 727 | Combined.DISPLAY_NORMAL + " END AS " + Combined.DISPLAY + ", " + |
michael@0 | 728 | qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + ", " + |
michael@0 | 729 | qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + ", " + |
michael@0 | 730 | qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + ", " + |
michael@0 | 731 | qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " AS " + Combined.FAVICON_ID + |
michael@0 | 732 | " FROM " + TABLE_HISTORY + " LEFT OUTER JOIN " + TABLE_BOOKMARKS + |
michael@0 | 733 | " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) + |
michael@0 | 734 | " WHERE " + qualifyColumn(TABLE_HISTORY, History.URL) + " IS NOT NULL AND " + |
michael@0 | 735 | qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND (" + |
michael@0 | 736 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " + |
michael@0 | 737 | qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK + ") " + |
michael@0 | 738 | ")"); |
michael@0 | 739 | |
michael@0 | 740 | debug("Creating " + VIEW_COMBINED_WITH_FAVICONS + " view"); |
michael@0 | 741 | |
michael@0 | 742 | db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED_WITH_FAVICONS + " AS" + |
michael@0 | 743 | " SELECT " + qualifyColumn(VIEW_COMBINED, "*") + ", " + |
michael@0 | 744 | qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Combined.FAVICON_URL + ", " + |
michael@0 | 745 | qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Combined.FAVICON + |
michael@0 | 746 | " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + TABLE_FAVICONS + |
michael@0 | 747 | " ON " + Combined.FAVICON_ID + " = " + qualifyColumn(TABLE_FAVICONS, Favicons._ID)); |
michael@0 | 748 | } |
michael@0 | 749 | |
michael@0 | 750 | @Override |
michael@0 | 751 | public void onCreate(SQLiteDatabase db) { |
michael@0 | 752 | debug("Creating browser.db: " + db.getPath()); |
michael@0 | 753 | |
michael@0 | 754 | createBookmarksTableOn13(db); |
michael@0 | 755 | createHistoryTableOn13(db); |
michael@0 | 756 | createFaviconsTable(db); |
michael@0 | 757 | createThumbnailsTable(db); |
michael@0 | 758 | |
michael@0 | 759 | createBookmarksWithFaviconsView(db); |
michael@0 | 760 | createHistoryWithFaviconsView(db); |
michael@0 | 761 | createCombinedViewOn16(db); |
michael@0 | 762 | |
michael@0 | 763 | createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID, |
michael@0 | 764 | R.string.bookmarks_folder_places, 0); |
michael@0 | 765 | |
michael@0 | 766 | createOrUpdateAllSpecialFolders(db); |
michael@0 | 767 | |
michael@0 | 768 | // Create distribution bookmarks before our own default bookmarks |
michael@0 | 769 | int pos = createDistributionBookmarks(db); |
michael@0 | 770 | createDefaultBookmarks(db, pos); |
michael@0 | 771 | |
michael@0 | 772 | createReadingListTable(db); |
michael@0 | 773 | } |
michael@0 | 774 | |
michael@0 | 775 | private String getLocalizedProperty(JSONObject bookmark, String property, Locale locale) throws JSONException { |
michael@0 | 776 | // Try the full locale |
michael@0 | 777 | String fullLocale = property + "." + locale.toString(); |
michael@0 | 778 | if (bookmark.has(fullLocale)) { |
michael@0 | 779 | return bookmark.getString(fullLocale); |
michael@0 | 780 | } |
michael@0 | 781 | // Try without a variant |
michael@0 | 782 | if (!TextUtils.isEmpty(locale.getVariant())) { |
michael@0 | 783 | String noVariant = fullLocale.substring(0, fullLocale.lastIndexOf("_")); |
michael@0 | 784 | if (bookmark.has(noVariant)) { |
michael@0 | 785 | return bookmark.getString(noVariant); |
michael@0 | 786 | } |
michael@0 | 787 | } |
michael@0 | 788 | // Try just the language |
michael@0 | 789 | String lang = property + "." + locale.getLanguage(); |
michael@0 | 790 | if (bookmark.has(lang)) { |
michael@0 | 791 | return bookmark.getString(lang); |
michael@0 | 792 | } |
michael@0 | 793 | // Default to the non-localized property name |
michael@0 | 794 | return bookmark.getString(property); |
michael@0 | 795 | } |
michael@0 | 796 | |
michael@0 | 797 | // Returns the number of bookmarks inserted in the db |
michael@0 | 798 | private int createDistributionBookmarks(SQLiteDatabase db) { |
michael@0 | 799 | JSONArray bookmarks = Distribution.getBookmarks(mContext); |
michael@0 | 800 | if (bookmarks == null) { |
michael@0 | 801 | return 0; |
michael@0 | 802 | } |
michael@0 | 803 | |
michael@0 | 804 | Locale locale = Locale.getDefault(); |
michael@0 | 805 | int pos = 0; |
michael@0 | 806 | Integer mobileFolderId = getMobileFolderId(db); |
michael@0 | 807 | if (mobileFolderId == null) { |
michael@0 | 808 | Log.e(LOGTAG, "Error creating distribution bookmarks: mobileFolderId is null"); |
michael@0 | 809 | return 0; |
michael@0 | 810 | } |
michael@0 | 811 | |
michael@0 | 812 | for (int i = 0; i < bookmarks.length(); i++) { |
michael@0 | 813 | try { |
michael@0 | 814 | final JSONObject bookmark = bookmarks.getJSONObject(i); |
michael@0 | 815 | |
michael@0 | 816 | String title = getLocalizedProperty(bookmark, "title", locale); |
michael@0 | 817 | final String url = getLocalizedProperty(bookmark, "url", locale); |
michael@0 | 818 | createBookmark(db, title, url, pos, mobileFolderId); |
michael@0 | 819 | |
michael@0 | 820 | if (bookmark.has("pinned")) { |
michael@0 | 821 | try { |
michael@0 | 822 | // Create a fake bookmark in the hidden pinned folder to pin bookmark |
michael@0 | 823 | // to about:home top sites. Pass pos as the pinned position to pin |
michael@0 | 824 | // sites in the order that bookmarks are specified in bookmarks.json. |
michael@0 | 825 | if (bookmark.getBoolean("pinned")) { |
michael@0 | 826 | createBookmark(db, title, url, pos, Bookmarks.FIXED_PINNED_LIST_ID); |
michael@0 | 827 | } |
michael@0 | 828 | } catch (JSONException e) { |
michael@0 | 829 | Log.e(LOGTAG, "Error pinning bookmark to top sites", e); |
michael@0 | 830 | } |
michael@0 | 831 | } |
michael@0 | 832 | |
michael@0 | 833 | pos++; |
michael@0 | 834 | |
michael@0 | 835 | // return early if there is no icon for this bookmark |
michael@0 | 836 | if (!bookmark.has("icon")) { |
michael@0 | 837 | continue; |
michael@0 | 838 | } |
michael@0 | 839 | |
michael@0 | 840 | // create icons in a separate thread to avoid blocking about:home on startup |
michael@0 | 841 | ThreadUtils.postToBackgroundThread(new Runnable() { |
michael@0 | 842 | @Override |
michael@0 | 843 | public void run() { |
michael@0 | 844 | SQLiteDatabase db = getWritableDatabase(); |
michael@0 | 845 | try { |
michael@0 | 846 | String iconData = bookmark.getString("icon"); |
michael@0 | 847 | Bitmap icon = BitmapUtils.getBitmapFromDataURI(iconData); |
michael@0 | 848 | if (icon != null) { |
michael@0 | 849 | createFavicon(db, url, icon); |
michael@0 | 850 | } |
michael@0 | 851 | } catch (JSONException e) { |
michael@0 | 852 | Log.e(LOGTAG, "Error creating distribution bookmark icon", e); |
michael@0 | 853 | } |
michael@0 | 854 | } |
michael@0 | 855 | }); |
michael@0 | 856 | } catch (JSONException e) { |
michael@0 | 857 | Log.e(LOGTAG, "Error creating distribution bookmark", e); |
michael@0 | 858 | } |
michael@0 | 859 | } |
michael@0 | 860 | return pos; |
michael@0 | 861 | } |
michael@0 | 862 | |
michael@0 | 863 | private void createReadingListTable(SQLiteDatabase db) { |
michael@0 | 864 | debug("Creating " + TABLE_READING_LIST + " table"); |
michael@0 | 865 | |
michael@0 | 866 | db.execSQL("CREATE TABLE " + TABLE_READING_LIST + "(" + |
michael@0 | 867 | ReadingListItems._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + |
michael@0 | 868 | ReadingListItems.URL + " TEXT NOT NULL, " + |
michael@0 | 869 | ReadingListItems.TITLE + " TEXT, " + |
michael@0 | 870 | ReadingListItems.EXCERPT + " TEXT, " + |
michael@0 | 871 | ReadingListItems.READ + " TINYINT DEFAULT 0, " + |
michael@0 | 872 | ReadingListItems.IS_DELETED + " TINYINT DEFAULT 0, " + |
michael@0 | 873 | ReadingListItems.GUID + " TEXT UNIQUE NOT NULL, " + |
michael@0 | 874 | ReadingListItems.DATE_MODIFIED + " INTEGER NOT NULL, " + |
michael@0 | 875 | ReadingListItems.DATE_CREATED + " INTEGER NOT NULL, " + |
michael@0 | 876 | ReadingListItems.LENGTH + " INTEGER DEFAULT 0 ); "); |
michael@0 | 877 | |
michael@0 | 878 | db.execSQL("CREATE INDEX reading_list_url ON " + TABLE_READING_LIST + "(" |
michael@0 | 879 | + ReadingListItems.URL + ")"); |
michael@0 | 880 | db.execSQL("CREATE UNIQUE INDEX reading_list_guid ON " + TABLE_READING_LIST + "(" |
michael@0 | 881 | + ReadingListItems.GUID + ")"); |
michael@0 | 882 | } |
michael@0 | 883 | |
michael@0 | 884 | // Inserts default bookmarks, starting at a specified position |
michael@0 | 885 | private void createDefaultBookmarks(SQLiteDatabase db, int pos) { |
michael@0 | 886 | Class<?> stringsClass = R.string.class; |
michael@0 | 887 | Field[] fields = stringsClass.getFields(); |
michael@0 | 888 | Pattern p = Pattern.compile("^bookmarkdefaults_title_"); |
michael@0 | 889 | |
michael@0 | 890 | Integer mobileFolderId = getMobileFolderId(db); |
michael@0 | 891 | if (mobileFolderId == null) { |
michael@0 | 892 | Log.e(LOGTAG, "Error creating default bookmarks: mobileFolderId is null"); |
michael@0 | 893 | return; |
michael@0 | 894 | } |
michael@0 | 895 | |
michael@0 | 896 | for (int i = 0; i < fields.length; i++) { |
michael@0 | 897 | final String name = fields[i].getName(); |
michael@0 | 898 | Matcher m = p.matcher(name); |
michael@0 | 899 | if (!m.find()) { |
michael@0 | 900 | continue; |
michael@0 | 901 | } |
michael@0 | 902 | try { |
michael@0 | 903 | int titleid = fields[i].getInt(null); |
michael@0 | 904 | String title = mContext.getString(titleid); |
michael@0 | 905 | |
michael@0 | 906 | Field urlField = stringsClass.getField(name.replace("_title_", "_url_")); |
michael@0 | 907 | int urlId = urlField.getInt(null); |
michael@0 | 908 | final String url = mContext.getString(urlId); |
michael@0 | 909 | createBookmark(db, title, url, pos, mobileFolderId); |
michael@0 | 910 | |
michael@0 | 911 | // create icons in a separate thread to avoid blocking about:home on startup |
michael@0 | 912 | ThreadUtils.postToBackgroundThread(new Runnable() { |
michael@0 | 913 | @Override |
michael@0 | 914 | public void run() { |
michael@0 | 915 | SQLiteDatabase db = getWritableDatabase(); |
michael@0 | 916 | Bitmap icon = getDefaultFaviconFromPath(name); |
michael@0 | 917 | if (icon == null) { |
michael@0 | 918 | icon = getDefaultFaviconFromDrawable(name); |
michael@0 | 919 | } |
michael@0 | 920 | if (icon != null) { |
michael@0 | 921 | createFavicon(db, url, icon); |
michael@0 | 922 | } |
michael@0 | 923 | } |
michael@0 | 924 | }); |
michael@0 | 925 | pos++; |
michael@0 | 926 | } catch (java.lang.IllegalAccessException ex) { |
michael@0 | 927 | Log.e(LOGTAG, "Can't create bookmark " + name, ex); |
michael@0 | 928 | } catch (java.lang.NoSuchFieldException ex) { |
michael@0 | 929 | Log.e(LOGTAG, "Can't create bookmark " + name, ex); |
michael@0 | 930 | } |
michael@0 | 931 | } |
michael@0 | 932 | } |
michael@0 | 933 | |
michael@0 | 934 | private void createBookmark(SQLiteDatabase db, String title, String url, int pos, int parent) { |
michael@0 | 935 | ContentValues bookmarkValues = new ContentValues(); |
michael@0 | 936 | bookmarkValues.put(Bookmarks.PARENT, parent); |
michael@0 | 937 | |
michael@0 | 938 | long now = System.currentTimeMillis(); |
michael@0 | 939 | bookmarkValues.put(Bookmarks.DATE_CREATED, now); |
michael@0 | 940 | bookmarkValues.put(Bookmarks.DATE_MODIFIED, now); |
michael@0 | 941 | |
michael@0 | 942 | bookmarkValues.put(Bookmarks.TITLE, title); |
michael@0 | 943 | bookmarkValues.put(Bookmarks.URL, url); |
michael@0 | 944 | bookmarkValues.put(Bookmarks.GUID, Utils.generateGuid()); |
michael@0 | 945 | bookmarkValues.put(Bookmarks.POSITION, pos); |
michael@0 | 946 | db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.TITLE, bookmarkValues); |
michael@0 | 947 | } |
michael@0 | 948 | |
michael@0 | 949 | private void createFavicon(SQLiteDatabase db, String url, Bitmap icon) { |
michael@0 | 950 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
michael@0 | 951 | |
michael@0 | 952 | ContentValues iconValues = new ContentValues(); |
michael@0 | 953 | iconValues.put(Favicons.PAGE_URL, url); |
michael@0 | 954 | |
michael@0 | 955 | byte[] data = null; |
michael@0 | 956 | if (icon.compress(Bitmap.CompressFormat.PNG, 100, stream)) { |
michael@0 | 957 | data = stream.toByteArray(); |
michael@0 | 958 | } else { |
michael@0 | 959 | Log.w(LOGTAG, "Favicon compression failed."); |
michael@0 | 960 | } |
michael@0 | 961 | iconValues.put(Favicons.DATA, data); |
michael@0 | 962 | |
michael@0 | 963 | insertFavicon(db, iconValues); |
michael@0 | 964 | } |
michael@0 | 965 | |
michael@0 | 966 | private Bitmap getDefaultFaviconFromPath(String name) { |
michael@0 | 967 | Class<?> stringClass = R.string.class; |
michael@0 | 968 | try { |
michael@0 | 969 | // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_* |
michael@0 | 970 | Field faviconField = stringClass.getField(name.replace("_title_", "_favicon_")); |
michael@0 | 971 | if (faviconField == null) { |
michael@0 | 972 | return null; |
michael@0 | 973 | } |
michael@0 | 974 | int faviconId = faviconField.getInt(null); |
michael@0 | 975 | String path = mContext.getString(faviconId); |
michael@0 | 976 | |
michael@0 | 977 | String apkPath = mContext.getPackageResourcePath(); |
michael@0 | 978 | File apkFile = new File(apkPath); |
michael@0 | 979 | String bitmapPath = "jar:jar:" + apkFile.toURI() + "!/" + AppConstants.OMNIJAR_NAME + "!/" + path; |
michael@0 | 980 | return GeckoJarReader.getBitmap(mContext.getResources(), bitmapPath); |
michael@0 | 981 | } catch (java.lang.IllegalAccessException ex) { |
michael@0 | 982 | Log.e(LOGTAG, "[Path] Can't create favicon " + name, ex); |
michael@0 | 983 | } catch (java.lang.NoSuchFieldException ex) { |
michael@0 | 984 | // If the field does not exist, that means we intend to load via a drawable |
michael@0 | 985 | } |
michael@0 | 986 | return null; |
michael@0 | 987 | } |
michael@0 | 988 | |
michael@0 | 989 | private Bitmap getDefaultFaviconFromDrawable(String name) { |
michael@0 | 990 | Class<?> drawablesClass = R.drawable.class; |
michael@0 | 991 | try { |
michael@0 | 992 | // Look for a drawable with the id R.drawable.bookmarkdefaults_favicon_* |
michael@0 | 993 | Field faviconField = drawablesClass.getField(name.replace("_title_", "_favicon_")); |
michael@0 | 994 | if (faviconField == null) { |
michael@0 | 995 | return null; |
michael@0 | 996 | } |
michael@0 | 997 | int faviconId = faviconField.getInt(null); |
michael@0 | 998 | return BitmapUtils.decodeResource(mContext, faviconId); |
michael@0 | 999 | } catch (java.lang.IllegalAccessException ex) { |
michael@0 | 1000 | Log.e(LOGTAG, "[Drawable] Can't create favicon " + name, ex); |
michael@0 | 1001 | } catch (java.lang.NoSuchFieldException ex) { |
michael@0 | 1002 | // If the field does not exist, that means we intend to load via a file path |
michael@0 | 1003 | } |
michael@0 | 1004 | return null; |
michael@0 | 1005 | } |
michael@0 | 1006 | |
michael@0 | 1007 | private void createOrUpdateAllSpecialFolders(SQLiteDatabase db) { |
michael@0 | 1008 | createOrUpdateSpecialFolder(db, Bookmarks.MOBILE_FOLDER_GUID, |
michael@0 | 1009 | R.string.bookmarks_folder_mobile, 0); |
michael@0 | 1010 | createOrUpdateSpecialFolder(db, Bookmarks.TOOLBAR_FOLDER_GUID, |
michael@0 | 1011 | R.string.bookmarks_folder_toolbar, 1); |
michael@0 | 1012 | createOrUpdateSpecialFolder(db, Bookmarks.MENU_FOLDER_GUID, |
michael@0 | 1013 | R.string.bookmarks_folder_menu, 2); |
michael@0 | 1014 | createOrUpdateSpecialFolder(db, Bookmarks.TAGS_FOLDER_GUID, |
michael@0 | 1015 | R.string.bookmarks_folder_tags, 3); |
michael@0 | 1016 | createOrUpdateSpecialFolder(db, Bookmarks.UNFILED_FOLDER_GUID, |
michael@0 | 1017 | R.string.bookmarks_folder_unfiled, 4); |
michael@0 | 1018 | createOrUpdateSpecialFolder(db, Bookmarks.READING_LIST_FOLDER_GUID, |
michael@0 | 1019 | R.string.bookmarks_folder_reading_list, 5); |
michael@0 | 1020 | createOrUpdateSpecialFolder(db, Bookmarks.PINNED_FOLDER_GUID, |
michael@0 | 1021 | R.string.bookmarks_folder_pinned, 6); |
michael@0 | 1022 | } |
michael@0 | 1023 | |
michael@0 | 1024 | private void createOrUpdateSpecialFolder(SQLiteDatabase db, |
michael@0 | 1025 | String guid, int titleId, int position) { |
michael@0 | 1026 | ContentValues values = new ContentValues(); |
michael@0 | 1027 | values.put(Bookmarks.GUID, guid); |
michael@0 | 1028 | values.put(Bookmarks.TYPE, Bookmarks.TYPE_FOLDER); |
michael@0 | 1029 | values.put(Bookmarks.POSITION, position); |
michael@0 | 1030 | |
michael@0 | 1031 | if (guid.equals(Bookmarks.PLACES_FOLDER_GUID)) |
michael@0 | 1032 | values.put(Bookmarks._ID, Bookmarks.FIXED_ROOT_ID); |
michael@0 | 1033 | else if (guid.equals(Bookmarks.READING_LIST_FOLDER_GUID)) |
michael@0 | 1034 | values.put(Bookmarks._ID, Bookmarks.FIXED_READING_LIST_ID); |
michael@0 | 1035 | else if (guid.equals(Bookmarks.PINNED_FOLDER_GUID)) |
michael@0 | 1036 | values.put(Bookmarks._ID, Bookmarks.FIXED_PINNED_LIST_ID); |
michael@0 | 1037 | |
michael@0 | 1038 | // Set the parent to 0, which sync assumes is the root |
michael@0 | 1039 | values.put(Bookmarks.PARENT, Bookmarks.FIXED_ROOT_ID); |
michael@0 | 1040 | |
michael@0 | 1041 | String title = mContext.getResources().getString(titleId); |
michael@0 | 1042 | values.put(Bookmarks.TITLE, title); |
michael@0 | 1043 | |
michael@0 | 1044 | long now = System.currentTimeMillis(); |
michael@0 | 1045 | values.put(Bookmarks.DATE_CREATED, now); |
michael@0 | 1046 | values.put(Bookmarks.DATE_MODIFIED, now); |
michael@0 | 1047 | |
michael@0 | 1048 | int updated = db.update(TABLE_BOOKMARKS, values, |
michael@0 | 1049 | Bookmarks.GUID + " = ?", |
michael@0 | 1050 | new String[] { guid }); |
michael@0 | 1051 | |
michael@0 | 1052 | if (updated == 0) { |
michael@0 | 1053 | db.insert(TABLE_BOOKMARKS, Bookmarks.GUID, values); |
michael@0 | 1054 | debug("Inserted special folder: " + guid); |
michael@0 | 1055 | } else { |
michael@0 | 1056 | debug("Updated special folder: " + guid); |
michael@0 | 1057 | } |
michael@0 | 1058 | } |
michael@0 | 1059 | |
michael@0 | 1060 | private boolean isSpecialFolder(ContentValues values) { |
michael@0 | 1061 | String guid = values.getAsString(Bookmarks.GUID); |
michael@0 | 1062 | if (guid == null) |
michael@0 | 1063 | return false; |
michael@0 | 1064 | |
michael@0 | 1065 | return guid.equals(Bookmarks.MOBILE_FOLDER_GUID) || |
michael@0 | 1066 | guid.equals(Bookmarks.MENU_FOLDER_GUID) || |
michael@0 | 1067 | guid.equals(Bookmarks.TOOLBAR_FOLDER_GUID) || |
michael@0 | 1068 | guid.equals(Bookmarks.UNFILED_FOLDER_GUID) || |
michael@0 | 1069 | guid.equals(Bookmarks.TAGS_FOLDER_GUID); |
michael@0 | 1070 | } |
michael@0 | 1071 | |
michael@0 | 1072 | private void migrateBookmarkFolder(SQLiteDatabase db, int folderId, |
michael@0 | 1073 | BookmarkMigrator migrator) { |
michael@0 | 1074 | Cursor c = null; |
michael@0 | 1075 | |
michael@0 | 1076 | debug("Migrating bookmark folder with id = " + folderId); |
michael@0 | 1077 | |
michael@0 | 1078 | String selection = Bookmarks.PARENT + " = " + folderId; |
michael@0 | 1079 | String[] selectionArgs = null; |
michael@0 | 1080 | |
michael@0 | 1081 | boolean isRootFolder = (folderId == Bookmarks.FIXED_ROOT_ID); |
michael@0 | 1082 | |
michael@0 | 1083 | // If we're loading the root folder, we have to account for |
michael@0 | 1084 | // any previously created special folder that was created without |
michael@0 | 1085 | // setting a parent id (e.g. mobile folder) and making sure we're |
michael@0 | 1086 | // not adding any infinite recursion as root's parent is root itself. |
michael@0 | 1087 | if (isRootFolder) { |
michael@0 | 1088 | selection = Bookmarks.GUID + " != ?" + " AND (" + |
michael@0 | 1089 | selection + " OR " + Bookmarks.PARENT + " = NULL)"; |
michael@0 | 1090 | selectionArgs = new String[] { Bookmarks.PLACES_FOLDER_GUID }; |
michael@0 | 1091 | } |
michael@0 | 1092 | |
michael@0 | 1093 | List<Integer> subFolders = new ArrayList<Integer>(); |
michael@0 | 1094 | List<ContentValues> invalidSpecialEntries = new ArrayList<ContentValues>(); |
michael@0 | 1095 | |
michael@0 | 1096 | try { |
michael@0 | 1097 | c = db.query(TABLE_BOOKMARKS_TMP, |
michael@0 | 1098 | null, |
michael@0 | 1099 | selection, |
michael@0 | 1100 | selectionArgs, |
michael@0 | 1101 | null, null, null); |
michael@0 | 1102 | |
michael@0 | 1103 | // The key point here is that bookmarks should be added in |
michael@0 | 1104 | // parent order to avoid any problems with the foreign key |
michael@0 | 1105 | // in Bookmarks.PARENT. |
michael@0 | 1106 | while (c.moveToNext()) { |
michael@0 | 1107 | ContentValues values = new ContentValues(); |
michael@0 | 1108 | |
michael@0 | 1109 | // We're using a null projection in the query which |
michael@0 | 1110 | // means we're getting all columns from the table. |
michael@0 | 1111 | // It's safe to simply transform the row into the |
michael@0 | 1112 | // values to be inserted on the new table. |
michael@0 | 1113 | DatabaseUtils.cursorRowToContentValues(c, values); |
michael@0 | 1114 | |
michael@0 | 1115 | boolean isSpecialFolder = isSpecialFolder(values); |
michael@0 | 1116 | |
michael@0 | 1117 | // The mobile folder used to be created with PARENT = NULL. |
michael@0 | 1118 | // We want fix that here. |
michael@0 | 1119 | if (values.getAsLong(Bookmarks.PARENT) == null && isSpecialFolder) |
michael@0 | 1120 | values.put(Bookmarks.PARENT, Bookmarks.FIXED_ROOT_ID); |
michael@0 | 1121 | |
michael@0 | 1122 | if (isRootFolder && !isSpecialFolder) { |
michael@0 | 1123 | invalidSpecialEntries.add(values); |
michael@0 | 1124 | continue; |
michael@0 | 1125 | } |
michael@0 | 1126 | |
michael@0 | 1127 | if (migrator != null) |
michael@0 | 1128 | migrator.updateForNewTable(values); |
michael@0 | 1129 | |
michael@0 | 1130 | debug("Migrating bookmark: " + values.getAsString(Bookmarks.TITLE)); |
michael@0 | 1131 | db.insert(TABLE_BOOKMARKS, Bookmarks.URL, values); |
michael@0 | 1132 | |
michael@0 | 1133 | Integer type = values.getAsInteger(Bookmarks.TYPE); |
michael@0 | 1134 | if (type != null && type == Bookmarks.TYPE_FOLDER) |
michael@0 | 1135 | subFolders.add(values.getAsInteger(Bookmarks._ID)); |
michael@0 | 1136 | } |
michael@0 | 1137 | } finally { |
michael@0 | 1138 | if (c != null) |
michael@0 | 1139 | c.close(); |
michael@0 | 1140 | } |
michael@0 | 1141 | |
michael@0 | 1142 | // At this point is safe to assume that the mobile folder is |
michael@0 | 1143 | // in the new table given that we've always created it on |
michael@0 | 1144 | // database creation time. |
michael@0 | 1145 | final int nInvalidSpecialEntries = invalidSpecialEntries.size(); |
michael@0 | 1146 | if (nInvalidSpecialEntries > 0) { |
michael@0 | 1147 | Integer mobileFolderId = getMobileFolderId(db); |
michael@0 | 1148 | if (mobileFolderId == null) { |
michael@0 | 1149 | Log.e(LOGTAG, "Error migrating invalid special folder entries: mobile folder id is null"); |
michael@0 | 1150 | return; |
michael@0 | 1151 | } |
michael@0 | 1152 | |
michael@0 | 1153 | debug("Found " + nInvalidSpecialEntries + " invalid special folder entries"); |
michael@0 | 1154 | for (int i = 0; i < nInvalidSpecialEntries; i++) { |
michael@0 | 1155 | ContentValues values = invalidSpecialEntries.get(i); |
michael@0 | 1156 | values.put(Bookmarks.PARENT, mobileFolderId); |
michael@0 | 1157 | |
michael@0 | 1158 | db.insert(TABLE_BOOKMARKS, Bookmarks.URL, values); |
michael@0 | 1159 | } |
michael@0 | 1160 | } |
michael@0 | 1161 | |
michael@0 | 1162 | final int nSubFolders = subFolders.size(); |
michael@0 | 1163 | for (int i = 0; i < nSubFolders; i++) { |
michael@0 | 1164 | int subFolderId = subFolders.get(i); |
michael@0 | 1165 | migrateBookmarkFolder(db, subFolderId, migrator); |
michael@0 | 1166 | } |
michael@0 | 1167 | } |
michael@0 | 1168 | |
michael@0 | 1169 | private void migrateBookmarksTable(SQLiteDatabase db) { |
michael@0 | 1170 | migrateBookmarksTable(db, null); |
michael@0 | 1171 | } |
michael@0 | 1172 | |
michael@0 | 1173 | private void migrateBookmarksTable(SQLiteDatabase db, BookmarkMigrator migrator) { |
michael@0 | 1174 | debug("Renaming bookmarks table to " + TABLE_BOOKMARKS_TMP); |
michael@0 | 1175 | db.execSQL("ALTER TABLE " + TABLE_BOOKMARKS + |
michael@0 | 1176 | " RENAME TO " + TABLE_BOOKMARKS_TMP); |
michael@0 | 1177 | |
michael@0 | 1178 | debug("Dropping views and indexes related to " + TABLE_BOOKMARKS); |
michael@0 | 1179 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES); |
michael@0 | 1180 | |
michael@0 | 1181 | db.execSQL("DROP INDEX IF EXISTS bookmarks_url_index"); |
michael@0 | 1182 | db.execSQL("DROP INDEX IF EXISTS bookmarks_type_deleted_index"); |
michael@0 | 1183 | db.execSQL("DROP INDEX IF EXISTS bookmarks_guid_index"); |
michael@0 | 1184 | db.execSQL("DROP INDEX IF EXISTS bookmarks_modified_index"); |
michael@0 | 1185 | |
michael@0 | 1186 | createBookmarksTable(db); |
michael@0 | 1187 | createBookmarksWithImagesView(db); |
michael@0 | 1188 | |
michael@0 | 1189 | createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID, |
michael@0 | 1190 | R.string.bookmarks_folder_places, 0); |
michael@0 | 1191 | |
michael@0 | 1192 | migrateBookmarkFolder(db, Bookmarks.FIXED_ROOT_ID, migrator); |
michael@0 | 1193 | |
michael@0 | 1194 | // Ensure all special folders exist and have the |
michael@0 | 1195 | // right folder hierarchy. |
michael@0 | 1196 | createOrUpdateAllSpecialFolders(db); |
michael@0 | 1197 | |
michael@0 | 1198 | debug("Dropping bookmarks temporary table"); |
michael@0 | 1199 | db.execSQL("DROP TABLE IF EXISTS " + TABLE_BOOKMARKS_TMP); |
michael@0 | 1200 | } |
michael@0 | 1201 | |
michael@0 | 1202 | |
michael@0 | 1203 | private void migrateHistoryTable(SQLiteDatabase db) { |
michael@0 | 1204 | debug("Renaming history table to " + TABLE_HISTORY_TMP); |
michael@0 | 1205 | db.execSQL("ALTER TABLE " + TABLE_HISTORY + |
michael@0 | 1206 | " RENAME TO " + TABLE_HISTORY_TMP); |
michael@0 | 1207 | |
michael@0 | 1208 | debug("Dropping views and indexes related to " + TABLE_HISTORY); |
michael@0 | 1209 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES); |
michael@0 | 1210 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1211 | |
michael@0 | 1212 | db.execSQL("DROP INDEX IF EXISTS history_url_index"); |
michael@0 | 1213 | db.execSQL("DROP INDEX IF EXISTS history_guid_index"); |
michael@0 | 1214 | db.execSQL("DROP INDEX IF EXISTS history_modified_index"); |
michael@0 | 1215 | db.execSQL("DROP INDEX IF EXISTS history_visited_index"); |
michael@0 | 1216 | |
michael@0 | 1217 | createHistoryTable(db); |
michael@0 | 1218 | createHistoryWithImagesView(db); |
michael@0 | 1219 | createCombinedWithImagesView(db); |
michael@0 | 1220 | |
michael@0 | 1221 | db.execSQL("INSERT INTO " + TABLE_HISTORY + " SELECT * FROM " + TABLE_HISTORY_TMP); |
michael@0 | 1222 | |
michael@0 | 1223 | debug("Dropping history temporary table"); |
michael@0 | 1224 | db.execSQL("DROP TABLE IF EXISTS " + TABLE_HISTORY_TMP); |
michael@0 | 1225 | } |
michael@0 | 1226 | |
michael@0 | 1227 | private void migrateImagesTable(SQLiteDatabase db) { |
michael@0 | 1228 | debug("Renaming images table to " + TABLE_IMAGES_TMP); |
michael@0 | 1229 | db.execSQL("ALTER TABLE " + Obsolete.TABLE_IMAGES + |
michael@0 | 1230 | " RENAME TO " + TABLE_IMAGES_TMP); |
michael@0 | 1231 | |
michael@0 | 1232 | debug("Dropping views and indexes related to " + Obsolete.TABLE_IMAGES); |
michael@0 | 1233 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES); |
michael@0 | 1234 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1235 | |
michael@0 | 1236 | db.execSQL("DROP INDEX IF EXISTS images_url_index"); |
michael@0 | 1237 | db.execSQL("DROP INDEX IF EXISTS images_guid_index"); |
michael@0 | 1238 | db.execSQL("DROP INDEX IF EXISTS images_modified_index"); |
michael@0 | 1239 | |
michael@0 | 1240 | createImagesTable(db); |
michael@0 | 1241 | createHistoryWithImagesView(db); |
michael@0 | 1242 | createCombinedWithImagesView(db); |
michael@0 | 1243 | |
michael@0 | 1244 | db.execSQL("INSERT INTO " + Obsolete.TABLE_IMAGES + " SELECT * FROM " + TABLE_IMAGES_TMP); |
michael@0 | 1245 | |
michael@0 | 1246 | debug("Dropping images temporary table"); |
michael@0 | 1247 | db.execSQL("DROP TABLE IF EXISTS " + TABLE_IMAGES_TMP); |
michael@0 | 1248 | } |
michael@0 | 1249 | |
michael@0 | 1250 | private void upgradeDatabaseFrom1to2(SQLiteDatabase db) { |
michael@0 | 1251 | migrateBookmarksTable(db); |
michael@0 | 1252 | } |
michael@0 | 1253 | |
michael@0 | 1254 | private void upgradeDatabaseFrom2to3(SQLiteDatabase db) { |
michael@0 | 1255 | debug("Dropping view: " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES); |
michael@0 | 1256 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES); |
michael@0 | 1257 | |
michael@0 | 1258 | createBookmarksWithImagesView(db); |
michael@0 | 1259 | |
michael@0 | 1260 | debug("Dropping view: " + Obsolete.VIEW_HISTORY_WITH_IMAGES); |
michael@0 | 1261 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES); |
michael@0 | 1262 | |
michael@0 | 1263 | createHistoryWithImagesView(db); |
michael@0 | 1264 | } |
michael@0 | 1265 | |
michael@0 | 1266 | private void upgradeDatabaseFrom3to4(SQLiteDatabase db) { |
michael@0 | 1267 | migrateBookmarksTable(db, new BookmarkMigrator3to4()); |
michael@0 | 1268 | } |
michael@0 | 1269 | |
michael@0 | 1270 | private void upgradeDatabaseFrom4to5(SQLiteDatabase db) { |
michael@0 | 1271 | createCombinedWithImagesView(db); |
michael@0 | 1272 | } |
michael@0 | 1273 | |
michael@0 | 1274 | private void upgradeDatabaseFrom5to6(SQLiteDatabase db) { |
michael@0 | 1275 | debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1276 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1277 | |
michael@0 | 1278 | createCombinedWithImagesView(db); |
michael@0 | 1279 | } |
michael@0 | 1280 | |
michael@0 | 1281 | private void upgradeDatabaseFrom6to7(SQLiteDatabase db) { |
michael@0 | 1282 | debug("Removing history visits with NULL GUIDs"); |
michael@0 | 1283 | db.execSQL("DELETE FROM " + TABLE_HISTORY + " WHERE " + History.GUID + " IS NULL"); |
michael@0 | 1284 | |
michael@0 | 1285 | debug("Update images with NULL GUIDs"); |
michael@0 | 1286 | String[] columns = new String[] { Obsolete.Images._ID }; |
michael@0 | 1287 | Cursor cursor = null; |
michael@0 | 1288 | try { |
michael@0 | 1289 | cursor = db.query(Obsolete.TABLE_IMAGES, columns, Obsolete.Images.GUID + " IS NULL", null, null ,null, null, null); |
michael@0 | 1290 | ContentValues values = new ContentValues(); |
michael@0 | 1291 | if (cursor.moveToFirst()) { |
michael@0 | 1292 | do { |
michael@0 | 1293 | values.put(Obsolete.Images.GUID, Utils.generateGuid()); |
michael@0 | 1294 | db.update(Obsolete.TABLE_IMAGES, values, Obsolete.Images._ID + " = ?", new String[] { |
michael@0 | 1295 | cursor.getString(cursor.getColumnIndexOrThrow(Obsolete.Images._ID)) |
michael@0 | 1296 | }); |
michael@0 | 1297 | } while (cursor.moveToNext()); |
michael@0 | 1298 | } |
michael@0 | 1299 | } finally { |
michael@0 | 1300 | if (cursor != null) |
michael@0 | 1301 | cursor.close(); |
michael@0 | 1302 | } |
michael@0 | 1303 | |
michael@0 | 1304 | migrateBookmarksTable(db); |
michael@0 | 1305 | migrateHistoryTable(db); |
michael@0 | 1306 | migrateImagesTable(db); |
michael@0 | 1307 | } |
michael@0 | 1308 | |
michael@0 | 1309 | private void upgradeDatabaseFrom7to8(SQLiteDatabase db) { |
michael@0 | 1310 | debug("Combining history entries with the same URL"); |
michael@0 | 1311 | |
michael@0 | 1312 | final String TABLE_DUPES = "duped_urls"; |
michael@0 | 1313 | final String TOTAL = "total"; |
michael@0 | 1314 | final String LATEST = "latest"; |
michael@0 | 1315 | final String WINNER = "winner"; |
michael@0 | 1316 | |
michael@0 | 1317 | db.execSQL("CREATE TEMP TABLE " + TABLE_DUPES + " AS" + |
michael@0 | 1318 | " SELECT " + History.URL + ", " + |
michael@0 | 1319 | "SUM(" + History.VISITS + ") AS " + TOTAL + ", " + |
michael@0 | 1320 | "MAX(" + History.DATE_MODIFIED + ") AS " + LATEST + ", " + |
michael@0 | 1321 | "MAX(" + History._ID + ") AS " + WINNER + |
michael@0 | 1322 | " FROM " + TABLE_HISTORY + |
michael@0 | 1323 | " GROUP BY " + History.URL + |
michael@0 | 1324 | " HAVING count(" + History.URL + ") > 1"); |
michael@0 | 1325 | |
michael@0 | 1326 | db.execSQL("CREATE UNIQUE INDEX " + TABLE_DUPES + "_url_index ON " + |
michael@0 | 1327 | TABLE_DUPES + " (" + History.URL + ")"); |
michael@0 | 1328 | |
michael@0 | 1329 | final String fromClause = " FROM " + TABLE_DUPES + " WHERE " + |
michael@0 | 1330 | qualifyColumn(TABLE_DUPES, History.URL) + " = " + |
michael@0 | 1331 | qualifyColumn(TABLE_HISTORY, History.URL); |
michael@0 | 1332 | |
michael@0 | 1333 | db.execSQL("UPDATE " + TABLE_HISTORY + |
michael@0 | 1334 | " SET " + History.VISITS + " = (SELECT " + TOTAL + fromClause + "), " + |
michael@0 | 1335 | History.DATE_MODIFIED + " = (SELECT " + LATEST + fromClause + "), " + |
michael@0 | 1336 | History.IS_DELETED + " = " + |
michael@0 | 1337 | "(" + History._ID + " <> (SELECT " + WINNER + fromClause + "))" + |
michael@0 | 1338 | " WHERE " + History.URL + " IN (SELECT " + History.URL + " FROM " + TABLE_DUPES + ")"); |
michael@0 | 1339 | |
michael@0 | 1340 | db.execSQL("DROP TABLE " + TABLE_DUPES); |
michael@0 | 1341 | } |
michael@0 | 1342 | |
michael@0 | 1343 | private void upgradeDatabaseFrom8to9(SQLiteDatabase db) { |
michael@0 | 1344 | createOrUpdateSpecialFolder(db, Bookmarks.READING_LIST_FOLDER_GUID, |
michael@0 | 1345 | R.string.bookmarks_folder_reading_list, 5); |
michael@0 | 1346 | |
michael@0 | 1347 | debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1348 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1349 | |
michael@0 | 1350 | createCombinedWithImagesViewOn9(db); |
michael@0 | 1351 | } |
michael@0 | 1352 | |
michael@0 | 1353 | private void upgradeDatabaseFrom9to10(SQLiteDatabase db) { |
michael@0 | 1354 | debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1355 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1356 | |
michael@0 | 1357 | createCombinedWithImagesViewOn10(db); |
michael@0 | 1358 | } |
michael@0 | 1359 | |
michael@0 | 1360 | private void upgradeDatabaseFrom10to11(SQLiteDatabase db) { |
michael@0 | 1361 | debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1362 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1363 | |
michael@0 | 1364 | db.execSQL("CREATE INDEX bookmarks_type_deleted_index ON " + TABLE_BOOKMARKS + "(" |
michael@0 | 1365 | + Bookmarks.TYPE + ", " + Bookmarks.IS_DELETED + ")"); |
michael@0 | 1366 | |
michael@0 | 1367 | createCombinedWithImagesViewOn11(db); |
michael@0 | 1368 | } |
michael@0 | 1369 | |
michael@0 | 1370 | private void upgradeDatabaseFrom11to12(SQLiteDatabase db) { |
michael@0 | 1371 | debug("Dropping view: " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1372 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1373 | |
michael@0 | 1374 | createCombinedViewOn12(db); |
michael@0 | 1375 | } |
michael@0 | 1376 | |
michael@0 | 1377 | private void upgradeDatabaseFrom12to13(SQLiteDatabase db) { |
michael@0 | 1378 | // Update images table with favicon URLs |
michael@0 | 1379 | SQLiteDatabase faviconsDb = null; |
michael@0 | 1380 | Cursor c = null; |
michael@0 | 1381 | try { |
michael@0 | 1382 | final String FAVICON_TABLE = "favicon_urls"; |
michael@0 | 1383 | final String FAVICON_URL = "favicon_url"; |
michael@0 | 1384 | final String FAVICON_PAGE = "page_url"; |
michael@0 | 1385 | |
michael@0 | 1386 | String dbPath = mContext.getDatabasePath(Obsolete.FAVICON_DB).getPath(); |
michael@0 | 1387 | faviconsDb = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY); |
michael@0 | 1388 | String[] columns = new String[] { FAVICON_URL, FAVICON_PAGE }; |
michael@0 | 1389 | c = faviconsDb.query(FAVICON_TABLE, columns, null, null, null, null, null, null); |
michael@0 | 1390 | int faviconIndex = c.getColumnIndexOrThrow(FAVICON_URL); |
michael@0 | 1391 | int pageIndex = c.getColumnIndexOrThrow(FAVICON_PAGE); |
michael@0 | 1392 | while (c.moveToNext()) { |
michael@0 | 1393 | ContentValues values = new ContentValues(1); |
michael@0 | 1394 | String faviconUrl = c.getString(faviconIndex); |
michael@0 | 1395 | String pageUrl = c.getString(pageIndex); |
michael@0 | 1396 | values.put(FAVICON_URL, faviconUrl); |
michael@0 | 1397 | db.update(Obsolete.TABLE_IMAGES, values, Obsolete.Images.URL + " = ?", new String[] { pageUrl }); |
michael@0 | 1398 | } |
michael@0 | 1399 | } catch (SQLException e) { |
michael@0 | 1400 | // If we can't read from the database for some reason, we won't |
michael@0 | 1401 | // be able to import the favicon URLs. This isn't a fatal |
michael@0 | 1402 | // error, so continue the upgrade. |
michael@0 | 1403 | Log.e(LOGTAG, "Exception importing from " + Obsolete.FAVICON_DB, e); |
michael@0 | 1404 | } finally { |
michael@0 | 1405 | if (c != null) |
michael@0 | 1406 | c.close(); |
michael@0 | 1407 | if (faviconsDb != null) |
michael@0 | 1408 | faviconsDb.close(); |
michael@0 | 1409 | } |
michael@0 | 1410 | |
michael@0 | 1411 | createFaviconsTable(db); |
michael@0 | 1412 | |
michael@0 | 1413 | // Import favicons into the favicons table |
michael@0 | 1414 | db.execSQL("ALTER TABLE " + TABLE_HISTORY |
michael@0 | 1415 | + " ADD COLUMN " + History.FAVICON_ID + " INTEGER"); |
michael@0 | 1416 | db.execSQL("ALTER TABLE " + TABLE_BOOKMARKS |
michael@0 | 1417 | + " ADD COLUMN " + Bookmarks.FAVICON_ID + " INTEGER"); |
michael@0 | 1418 | |
michael@0 | 1419 | try { |
michael@0 | 1420 | c = db.query(Obsolete.TABLE_IMAGES, |
michael@0 | 1421 | new String[] { |
michael@0 | 1422 | Obsolete.Images.URL, |
michael@0 | 1423 | Obsolete.Images.FAVICON_URL, |
michael@0 | 1424 | Obsolete.Images.FAVICON, |
michael@0 | 1425 | Obsolete.Images.DATE_MODIFIED, |
michael@0 | 1426 | Obsolete.Images.DATE_CREATED |
michael@0 | 1427 | }, |
michael@0 | 1428 | Obsolete.Images.FAVICON + " IS NOT NULL", |
michael@0 | 1429 | null, null, null, null); |
michael@0 | 1430 | |
michael@0 | 1431 | while (c.moveToNext()) { |
michael@0 | 1432 | long faviconId = -1; |
michael@0 | 1433 | int faviconUrlIndex = c.getColumnIndexOrThrow(Obsolete.Images.FAVICON_URL); |
michael@0 | 1434 | String faviconUrl = null; |
michael@0 | 1435 | if (!c.isNull(faviconUrlIndex)) { |
michael@0 | 1436 | faviconUrl = c.getString(faviconUrlIndex); |
michael@0 | 1437 | Cursor c2 = null; |
michael@0 | 1438 | try { |
michael@0 | 1439 | c2 = db.query(TABLE_FAVICONS, |
michael@0 | 1440 | new String[] { Favicons._ID }, |
michael@0 | 1441 | Favicons.URL + " = ?", |
michael@0 | 1442 | new String[] { faviconUrl }, |
michael@0 | 1443 | null, null, null); |
michael@0 | 1444 | if (c2.moveToFirst()) { |
michael@0 | 1445 | faviconId = c2.getLong(c2.getColumnIndexOrThrow(Favicons._ID)); |
michael@0 | 1446 | } |
michael@0 | 1447 | } finally { |
michael@0 | 1448 | if (c2 != null) |
michael@0 | 1449 | c2.close(); |
michael@0 | 1450 | } |
michael@0 | 1451 | } |
michael@0 | 1452 | |
michael@0 | 1453 | if (faviconId == -1) { |
michael@0 | 1454 | ContentValues values = new ContentValues(4); |
michael@0 | 1455 | values.put(Favicons.URL, faviconUrl); |
michael@0 | 1456 | values.put(Favicons.DATA, c.getBlob(c.getColumnIndexOrThrow(Obsolete.Images.FAVICON))); |
michael@0 | 1457 | values.put(Favicons.DATE_MODIFIED, c.getLong(c.getColumnIndexOrThrow(Obsolete.Images.DATE_MODIFIED))); |
michael@0 | 1458 | values.put(Favicons.DATE_CREATED, c.getLong(c.getColumnIndexOrThrow(Obsolete.Images.DATE_CREATED))); |
michael@0 | 1459 | faviconId = db.insert(TABLE_FAVICONS, null, values); |
michael@0 | 1460 | } |
michael@0 | 1461 | |
michael@0 | 1462 | ContentValues values = new ContentValues(1); |
michael@0 | 1463 | values.put(FaviconColumns.FAVICON_ID, faviconId); |
michael@0 | 1464 | db.update(TABLE_HISTORY, values, History.URL + " = ?", |
michael@0 | 1465 | new String[] { c.getString(c.getColumnIndexOrThrow(Obsolete.Images.URL)) }); |
michael@0 | 1466 | db.update(TABLE_BOOKMARKS, values, Bookmarks.URL + " = ?", |
michael@0 | 1467 | new String[] { c.getString(c.getColumnIndexOrThrow(Obsolete.Images.URL)) }); |
michael@0 | 1468 | } |
michael@0 | 1469 | } finally { |
michael@0 | 1470 | if (c != null) |
michael@0 | 1471 | c.close(); |
michael@0 | 1472 | } |
michael@0 | 1473 | |
michael@0 | 1474 | createThumbnailsTable(db); |
michael@0 | 1475 | |
michael@0 | 1476 | // Import thumbnails into the thumbnails table |
michael@0 | 1477 | db.execSQL("INSERT INTO " + TABLE_THUMBNAILS + " (" |
michael@0 | 1478 | + Thumbnails.URL + ", " |
michael@0 | 1479 | + Thumbnails.DATA + ") " |
michael@0 | 1480 | + "SELECT " + Obsolete.Images.URL + ", " + Obsolete.Images.THUMBNAIL |
michael@0 | 1481 | + " FROM " + Obsolete.TABLE_IMAGES |
michael@0 | 1482 | + " WHERE " + Obsolete.Images.THUMBNAIL + " IS NOT NULL"); |
michael@0 | 1483 | |
michael@0 | 1484 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_BOOKMARKS_WITH_IMAGES); |
michael@0 | 1485 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_HISTORY_WITH_IMAGES); |
michael@0 | 1486 | db.execSQL("DROP VIEW IF EXISTS " + Obsolete.VIEW_COMBINED_WITH_IMAGES); |
michael@0 | 1487 | db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED); |
michael@0 | 1488 | |
michael@0 | 1489 | createBookmarksWithFaviconsView(db); |
michael@0 | 1490 | createHistoryWithFaviconsView(db); |
michael@0 | 1491 | createCombinedViewOn13(db); |
michael@0 | 1492 | |
michael@0 | 1493 | db.execSQL("DROP TABLE IF EXISTS " + Obsolete.TABLE_IMAGES); |
michael@0 | 1494 | } |
michael@0 | 1495 | |
michael@0 | 1496 | private void upgradeDatabaseFrom13to14(SQLiteDatabase db) { |
michael@0 | 1497 | createOrUpdateSpecialFolder(db, Bookmarks.PINNED_FOLDER_GUID, |
michael@0 | 1498 | R.string.bookmarks_folder_pinned, 6); |
michael@0 | 1499 | } |
michael@0 | 1500 | |
michael@0 | 1501 | private void upgradeDatabaseFrom14to15(SQLiteDatabase db) { |
michael@0 | 1502 | Cursor c = null; |
michael@0 | 1503 | try { |
michael@0 | 1504 | // Get all the pinned bookmarks |
michael@0 | 1505 | c = db.query(TABLE_BOOKMARKS, |
michael@0 | 1506 | new String[] { Bookmarks._ID, Bookmarks.URL }, |
michael@0 | 1507 | Bookmarks.PARENT + " = ?", |
michael@0 | 1508 | new String[] { Integer.toString(Bookmarks.FIXED_PINNED_LIST_ID) }, |
michael@0 | 1509 | null, null, null); |
michael@0 | 1510 | |
michael@0 | 1511 | while (c.moveToNext()) { |
michael@0 | 1512 | // Check if this URL can be parsed as a URI with a valid scheme. |
michael@0 | 1513 | String url = c.getString(c.getColumnIndexOrThrow(Bookmarks.URL)); |
michael@0 | 1514 | if (Uri.parse(url).getScheme() != null) { |
michael@0 | 1515 | continue; |
michael@0 | 1516 | } |
michael@0 | 1517 | |
michael@0 | 1518 | // If it can't, update the URL to be an encoded "user-entered" value. |
michael@0 | 1519 | ContentValues values = new ContentValues(1); |
michael@0 | 1520 | String newUrl = Uri.fromParts("user-entered", url, null).toString(); |
michael@0 | 1521 | values.put(Bookmarks.URL, newUrl); |
michael@0 | 1522 | db.update(TABLE_BOOKMARKS, values, Bookmarks._ID + " = ?", |
michael@0 | 1523 | new String[] { Integer.toString(c.getInt(c.getColumnIndexOrThrow(Bookmarks._ID))) }); |
michael@0 | 1524 | } |
michael@0 | 1525 | } finally { |
michael@0 | 1526 | if (c != null) { |
michael@0 | 1527 | c.close(); |
michael@0 | 1528 | } |
michael@0 | 1529 | } |
michael@0 | 1530 | } |
michael@0 | 1531 | |
michael@0 | 1532 | private void upgradeDatabaseFrom15to16(SQLiteDatabase db) { |
michael@0 | 1533 | db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED); |
michael@0 | 1534 | db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS); |
michael@0 | 1535 | |
michael@0 | 1536 | createCombinedViewOn16(db); |
michael@0 | 1537 | } |
michael@0 | 1538 | |
michael@0 | 1539 | private void upgradeDatabaseFrom16to17(SQLiteDatabase db) { |
michael@0 | 1540 | // Purge any 0-byte favicons/thumbnails |
michael@0 | 1541 | try { |
michael@0 | 1542 | db.execSQL("DELETE FROM " + TABLE_FAVICONS + |
michael@0 | 1543 | " WHERE length(" + Favicons.DATA + ") = 0"); |
michael@0 | 1544 | db.execSQL("DELETE FROM " + TABLE_THUMBNAILS + |
michael@0 | 1545 | " WHERE length(" + Thumbnails.DATA + ") = 0"); |
michael@0 | 1546 | } catch (SQLException e) { |
michael@0 | 1547 | Log.e(LOGTAG, "Error purging invalid favicons or thumbnails", e); |
michael@0 | 1548 | } |
michael@0 | 1549 | } |
michael@0 | 1550 | |
michael@0 | 1551 | /* |
michael@0 | 1552 | * Moves reading list items from 'bookmarks' table to 'reading_list' table. Uses the |
michael@0 | 1553 | * same item GUID. |
michael@0 | 1554 | */ |
michael@0 | 1555 | private void upgradeDatabaseFrom17to18(SQLiteDatabase db) { |
michael@0 | 1556 | debug("Moving reading list items from 'bookmarks' table to 'reading_list' table"); |
michael@0 | 1557 | |
michael@0 | 1558 | final String selection = Bookmarks.PARENT + " = ? AND " + Bookmarks.IS_DELETED + " = ? "; |
michael@0 | 1559 | final String[] selectionArgs = { String.valueOf(Bookmarks.FIXED_READING_LIST_ID), "0" }; |
michael@0 | 1560 | final String[] projection = { Bookmarks._ID, |
michael@0 | 1561 | Bookmarks.GUID, |
michael@0 | 1562 | Bookmarks.URL, |
michael@0 | 1563 | Bookmarks.DATE_MODIFIED, |
michael@0 | 1564 | Bookmarks.DATE_CREATED, |
michael@0 | 1565 | Bookmarks.TITLE }; |
michael@0 | 1566 | Cursor cursor = null; |
michael@0 | 1567 | try { |
michael@0 | 1568 | // Start transaction |
michael@0 | 1569 | db.beginTransaction(); |
michael@0 | 1570 | |
michael@0 | 1571 | // Create 'reading_list' table |
michael@0 | 1572 | createReadingListTable(db); |
michael@0 | 1573 | |
michael@0 | 1574 | // Get all the reading list items from bookmarks table |
michael@0 | 1575 | cursor = db.query(TABLE_BOOKMARKS, projection, selection, selectionArgs, |
michael@0 | 1576 | null, null, null); |
michael@0 | 1577 | |
michael@0 | 1578 | // Insert reading list items into reading_list table |
michael@0 | 1579 | while (cursor.moveToNext()) { |
michael@0 | 1580 | debug(DatabaseUtils.dumpCurrentRowToString(cursor)); |
michael@0 | 1581 | ContentValues values = new ContentValues(); |
michael@0 | 1582 | DatabaseUtils.cursorStringToContentValues(cursor, Bookmarks.URL, values, ReadingListItems.URL); |
michael@0 | 1583 | DatabaseUtils.cursorStringToContentValues(cursor, Bookmarks.GUID, values, ReadingListItems.GUID); |
michael@0 | 1584 | DatabaseUtils.cursorStringToContentValues(cursor, Bookmarks.TITLE, values, ReadingListItems.TITLE); |
michael@0 | 1585 | DatabaseUtils.cursorLongToContentValues(cursor, Bookmarks.DATE_CREATED, values, ReadingListItems.DATE_CREATED); |
michael@0 | 1586 | DatabaseUtils.cursorLongToContentValues(cursor, Bookmarks.DATE_MODIFIED, values, ReadingListItems.DATE_MODIFIED); |
michael@0 | 1587 | |
michael@0 | 1588 | db.insertOrThrow(TABLE_READING_LIST, null, values); |
michael@0 | 1589 | } |
michael@0 | 1590 | |
michael@0 | 1591 | // Delete reading list items from bookmarks table |
michael@0 | 1592 | db.delete(TABLE_BOOKMARKS, |
michael@0 | 1593 | Bookmarks.PARENT + " = ? ", |
michael@0 | 1594 | new String[] { String.valueOf(Bookmarks.FIXED_READING_LIST_ID) }); |
michael@0 | 1595 | |
michael@0 | 1596 | // Delete reading list special folder |
michael@0 | 1597 | db.delete(TABLE_BOOKMARKS, |
michael@0 | 1598 | Bookmarks._ID + " = ? ", |
michael@0 | 1599 | new String[] { String.valueOf(Bookmarks.FIXED_READING_LIST_ID) }); |
michael@0 | 1600 | // Done |
michael@0 | 1601 | db.setTransactionSuccessful(); |
michael@0 | 1602 | |
michael@0 | 1603 | } catch (SQLException e) { |
michael@0 | 1604 | Log.e(LOGTAG, "Error migrating reading list items", e); |
michael@0 | 1605 | } finally { |
michael@0 | 1606 | if (cursor != null) { |
michael@0 | 1607 | cursor.close(); |
michael@0 | 1608 | } |
michael@0 | 1609 | db.endTransaction(); |
michael@0 | 1610 | } |
michael@0 | 1611 | } |
michael@0 | 1612 | |
michael@0 | 1613 | @Override |
michael@0 | 1614 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
michael@0 | 1615 | debug("Upgrading browser.db: " + db.getPath() + " from " + |
michael@0 | 1616 | oldVersion + " to " + newVersion); |
michael@0 | 1617 | |
michael@0 | 1618 | // We have to do incremental upgrades until we reach the current |
michael@0 | 1619 | // database schema version. |
michael@0 | 1620 | for (int v = oldVersion + 1; v <= newVersion; v++) { |
michael@0 | 1621 | switch(v) { |
michael@0 | 1622 | case 2: |
michael@0 | 1623 | upgradeDatabaseFrom1to2(db); |
michael@0 | 1624 | break; |
michael@0 | 1625 | |
michael@0 | 1626 | case 3: |
michael@0 | 1627 | upgradeDatabaseFrom2to3(db); |
michael@0 | 1628 | break; |
michael@0 | 1629 | |
michael@0 | 1630 | case 4: |
michael@0 | 1631 | upgradeDatabaseFrom3to4(db); |
michael@0 | 1632 | break; |
michael@0 | 1633 | |
michael@0 | 1634 | case 5: |
michael@0 | 1635 | upgradeDatabaseFrom4to5(db); |
michael@0 | 1636 | break; |
michael@0 | 1637 | |
michael@0 | 1638 | case 6: |
michael@0 | 1639 | upgradeDatabaseFrom5to6(db); |
michael@0 | 1640 | break; |
michael@0 | 1641 | |
michael@0 | 1642 | case 7: |
michael@0 | 1643 | upgradeDatabaseFrom6to7(db); |
michael@0 | 1644 | break; |
michael@0 | 1645 | |
michael@0 | 1646 | case 8: |
michael@0 | 1647 | upgradeDatabaseFrom7to8(db); |
michael@0 | 1648 | break; |
michael@0 | 1649 | |
michael@0 | 1650 | case 9: |
michael@0 | 1651 | upgradeDatabaseFrom8to9(db); |
michael@0 | 1652 | break; |
michael@0 | 1653 | |
michael@0 | 1654 | case 10: |
michael@0 | 1655 | upgradeDatabaseFrom9to10(db); |
michael@0 | 1656 | break; |
michael@0 | 1657 | |
michael@0 | 1658 | case 11: |
michael@0 | 1659 | upgradeDatabaseFrom10to11(db); |
michael@0 | 1660 | break; |
michael@0 | 1661 | |
michael@0 | 1662 | case 12: |
michael@0 | 1663 | upgradeDatabaseFrom11to12(db); |
michael@0 | 1664 | break; |
michael@0 | 1665 | |
michael@0 | 1666 | case 13: |
michael@0 | 1667 | upgradeDatabaseFrom12to13(db); |
michael@0 | 1668 | break; |
michael@0 | 1669 | |
michael@0 | 1670 | case 14: |
michael@0 | 1671 | upgradeDatabaseFrom13to14(db); |
michael@0 | 1672 | break; |
michael@0 | 1673 | |
michael@0 | 1674 | case 15: |
michael@0 | 1675 | upgradeDatabaseFrom14to15(db); |
michael@0 | 1676 | break; |
michael@0 | 1677 | |
michael@0 | 1678 | case 16: |
michael@0 | 1679 | upgradeDatabaseFrom15to16(db); |
michael@0 | 1680 | break; |
michael@0 | 1681 | |
michael@0 | 1682 | case 17: |
michael@0 | 1683 | upgradeDatabaseFrom16to17(db); |
michael@0 | 1684 | break; |
michael@0 | 1685 | |
michael@0 | 1686 | case 18: |
michael@0 | 1687 | upgradeDatabaseFrom17to18(db); |
michael@0 | 1688 | break; |
michael@0 | 1689 | } |
michael@0 | 1690 | } |
michael@0 | 1691 | |
michael@0 | 1692 | // If an upgrade after 12->13 fails, the entire upgrade is rolled |
michael@0 | 1693 | // back, but we can't undo the deletion of favicon_urls.db if we |
michael@0 | 1694 | // delete this in step 13; therefore, we wait until all steps are |
michael@0 | 1695 | // complete before removing it. |
michael@0 | 1696 | if (oldVersion < 13 && newVersion >= 13 |
michael@0 | 1697 | && mContext.getDatabasePath(Obsolete.FAVICON_DB).exists() |
michael@0 | 1698 | && !mContext.deleteDatabase(Obsolete.FAVICON_DB)) { |
michael@0 | 1699 | throw new SQLException("Could not delete " + Obsolete.FAVICON_DB); |
michael@0 | 1700 | } |
michael@0 | 1701 | } |
michael@0 | 1702 | |
michael@0 | 1703 | @Override |
michael@0 | 1704 | public void onOpen(SQLiteDatabase db) { |
michael@0 | 1705 | debug("Opening browser.db: " + db.getPath()); |
michael@0 | 1706 | |
michael@0 | 1707 | Cursor cursor = null; |
michael@0 | 1708 | try { |
michael@0 | 1709 | cursor = db.rawQuery("PRAGMA foreign_keys=ON", null); |
michael@0 | 1710 | } finally { |
michael@0 | 1711 | if (cursor != null) |
michael@0 | 1712 | cursor.close(); |
michael@0 | 1713 | } |
michael@0 | 1714 | cursor = null; |
michael@0 | 1715 | try { |
michael@0 | 1716 | cursor = db.rawQuery("PRAGMA synchronous=NORMAL", null); |
michael@0 | 1717 | } finally { |
michael@0 | 1718 | if (cursor != null) |
michael@0 | 1719 | cursor.close(); |
michael@0 | 1720 | } |
michael@0 | 1721 | |
michael@0 | 1722 | // From Honeycomb on, it's possible to run several db |
michael@0 | 1723 | // commands in parallel using multiple connections. |
michael@0 | 1724 | if (Build.VERSION.SDK_INT >= 11) { |
michael@0 | 1725 | db.enableWriteAheadLogging(); |
michael@0 | 1726 | db.setLockingEnabled(false); |
michael@0 | 1727 | } else { |
michael@0 | 1728 | // Pre-Honeycomb, we can do some lesser optimizations. |
michael@0 | 1729 | cursor = null; |
michael@0 | 1730 | try { |
michael@0 | 1731 | cursor = db.rawQuery("PRAGMA journal_mode=PERSIST", null); |
michael@0 | 1732 | } finally { |
michael@0 | 1733 | if (cursor != null) |
michael@0 | 1734 | cursor.close(); |
michael@0 | 1735 | } |
michael@0 | 1736 | } |
michael@0 | 1737 | } |
michael@0 | 1738 | |
michael@0 | 1739 | static final String qualifyColumn(String table, String column) { |
michael@0 | 1740 | return DBUtils.qualifyColumn(table, column); |
michael@0 | 1741 | } |
michael@0 | 1742 | |
michael@0 | 1743 | // Calculate these once, at initialization. isLoggable is too expensive to |
michael@0 | 1744 | // have in-line in each log call. |
michael@0 | 1745 | private static boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG); |
michael@0 | 1746 | private static boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE); |
michael@0 | 1747 | protected static void trace(String message) { |
michael@0 | 1748 | if (logVerbose) { |
michael@0 | 1749 | Log.v(LOGTAG, message); |
michael@0 | 1750 | } |
michael@0 | 1751 | } |
michael@0 | 1752 | |
michael@0 | 1753 | protected static void debug(String message) { |
michael@0 | 1754 | if (logDebug) { |
michael@0 | 1755 | Log.d(LOGTAG, message); |
michael@0 | 1756 | } |
michael@0 | 1757 | } |
michael@0 | 1758 | |
michael@0 | 1759 | private Integer getMobileFolderId(SQLiteDatabase db) { |
michael@0 | 1760 | Cursor c = null; |
michael@0 | 1761 | |
michael@0 | 1762 | try { |
michael@0 | 1763 | c = db.query(TABLE_BOOKMARKS, |
michael@0 | 1764 | mobileIdColumns, |
michael@0 | 1765 | Bookmarks.GUID + " = ?", |
michael@0 | 1766 | mobileIdSelectionArgs, |
michael@0 | 1767 | null, null, null); |
michael@0 | 1768 | |
michael@0 | 1769 | if (c == null || !c.moveToFirst()) |
michael@0 | 1770 | return null; |
michael@0 | 1771 | |
michael@0 | 1772 | return c.getInt(c.getColumnIndex(Bookmarks._ID)); |
michael@0 | 1773 | } finally { |
michael@0 | 1774 | if (c != null) |
michael@0 | 1775 | c.close(); |
michael@0 | 1776 | } |
michael@0 | 1777 | } |
michael@0 | 1778 | |
michael@0 | 1779 | private long insertFavicon(SQLiteDatabase db, ContentValues values) { |
michael@0 | 1780 | // This method is a dupicate of BrowserProvider.insertFavicon. |
michael@0 | 1781 | // If changes are needed, please update both |
michael@0 | 1782 | String faviconUrl = values.getAsString(Favicons.URL); |
michael@0 | 1783 | String pageUrl = null; |
michael@0 | 1784 | long faviconId; |
michael@0 | 1785 | |
michael@0 | 1786 | trace("Inserting favicon for URL: " + faviconUrl); |
michael@0 | 1787 | |
michael@0 | 1788 | DBUtils.stripEmptyByteArray(values, Favicons.DATA); |
michael@0 | 1789 | |
michael@0 | 1790 | // Extract the page URL from the ContentValues |
michael@0 | 1791 | if (values.containsKey(Favicons.PAGE_URL)) { |
michael@0 | 1792 | pageUrl = values.getAsString(Favicons.PAGE_URL); |
michael@0 | 1793 | values.remove(Favicons.PAGE_URL); |
michael@0 | 1794 | } |
michael@0 | 1795 | |
michael@0 | 1796 | // If no URL is provided, insert using the default one. |
michael@0 | 1797 | if (TextUtils.isEmpty(faviconUrl) && !TextUtils.isEmpty(pageUrl)) { |
michael@0 | 1798 | values.put(Favicons.URL, org.mozilla.gecko.favicons.Favicons.guessDefaultFaviconURL(pageUrl)); |
michael@0 | 1799 | } |
michael@0 | 1800 | |
michael@0 | 1801 | long now = System.currentTimeMillis(); |
michael@0 | 1802 | values.put(Favicons.DATE_CREATED, now); |
michael@0 | 1803 | values.put(Favicons.DATE_MODIFIED, now); |
michael@0 | 1804 | faviconId = db.insertOrThrow(TABLE_FAVICONS, null, values); |
michael@0 | 1805 | |
michael@0 | 1806 | if (pageUrl != null) { |
michael@0 | 1807 | ContentValues updateValues = new ContentValues(1); |
michael@0 | 1808 | updateValues.put(FaviconColumns.FAVICON_ID, faviconId); |
michael@0 | 1809 | db.update(TABLE_HISTORY, |
michael@0 | 1810 | updateValues, |
michael@0 | 1811 | History.URL + " = ?", |
michael@0 | 1812 | new String[] { pageUrl }); |
michael@0 | 1813 | db.update(TABLE_BOOKMARKS, |
michael@0 | 1814 | updateValues, |
michael@0 | 1815 | Bookmarks.URL + " = ?", |
michael@0 | 1816 | new String[] { pageUrl }); |
michael@0 | 1817 | } |
michael@0 | 1818 | |
michael@0 | 1819 | return faviconId; |
michael@0 | 1820 | } |
michael@0 | 1821 | |
michael@0 | 1822 | private interface BookmarkMigrator { |
michael@0 | 1823 | public void updateForNewTable(ContentValues bookmark); |
michael@0 | 1824 | } |
michael@0 | 1825 | |
michael@0 | 1826 | private class BookmarkMigrator3to4 implements BookmarkMigrator { |
michael@0 | 1827 | @Override |
michael@0 | 1828 | public void updateForNewTable(ContentValues bookmark) { |
michael@0 | 1829 | Integer isFolder = bookmark.getAsInteger("folder"); |
michael@0 | 1830 | if (isFolder == null || isFolder != 1) { |
michael@0 | 1831 | bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_BOOKMARK); |
michael@0 | 1832 | } else { |
michael@0 | 1833 | bookmark.put(Bookmarks.TYPE, Bookmarks.TYPE_FOLDER); |
michael@0 | 1834 | } |
michael@0 | 1835 | |
michael@0 | 1836 | bookmark.remove("folder"); |
michael@0 | 1837 | } |
michael@0 | 1838 | } |
michael@0 | 1839 | } |