1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 2 * This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 package org.mozilla.gecko.db; 7 8 import org.mozilla.gecko.AppConstants; 9 10 import android.net.Uri; 11 import android.support.annotation.IntDef; 12 import android.support.annotation.NonNull; 13 14 import org.mozilla.gecko.annotation.RobocopTarget; 15 16 @RobocopTarget 17 public class BrowserContract { 18 public static final String AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.browser"; 19 public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); 20 21 public static final String PASSWORDS_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.passwords"; 22 public static final Uri PASSWORDS_AUTHORITY_URI = Uri.parse("content://" + PASSWORDS_AUTHORITY); 23 24 public static final String FORM_HISTORY_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.formhistory"; 25 public static final Uri FORM_HISTORY_AUTHORITY_URI = Uri.parse("content://" + FORM_HISTORY_AUTHORITY); 26 27 public static final String TABS_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.tabs"; 28 public static final Uri TABS_AUTHORITY_URI = Uri.parse("content://" + TABS_AUTHORITY); 29 30 public static final String HOME_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.home"; 31 public static final Uri HOME_AUTHORITY_URI = Uri.parse("content://" + HOME_AUTHORITY); 32 33 public static final String PROFILES_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".profiles"; 34 public static final Uri PROFILES_AUTHORITY_URI = Uri.parse("content://" + PROFILES_AUTHORITY); 35 36 public static final String READING_LIST_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.readinglist"; 37 public static final Uri READING_LIST_AUTHORITY_URI = Uri.parse("content://" + READING_LIST_AUTHORITY); 38 39 public static final String SEARCH_HISTORY_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.searchhistory"; 40 public static final Uri SEARCH_HISTORY_AUTHORITY_URI = Uri.parse("content://" + SEARCH_HISTORY_AUTHORITY); 41 42 public static final String LOGINS_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.logins"; 43 public static final Uri LOGINS_AUTHORITY_URI = Uri.parse("content://" + LOGINS_AUTHORITY); 44 45 public static final String PARAM_PROFILE = "profile"; 46 public static final String PARAM_PROFILE_PATH = "profilePath"; 47 public static final String PARAM_LIMIT = "limit"; 48 public static final String PARAM_SUGGESTEDSITES_LIMIT = "suggestedsites_limit"; 49 public static final String PARAM_TOPSITES_EXCLUDE_REMOTE_ONLY = "topsites_exclude_remote_only"; 50 public static final String PARAM_IS_SYNC = "sync"; 51 public static final String PARAM_SHOW_DELETED = "show_deleted"; 52 public static final String PARAM_IS_TEST = "test"; 53 public static final String PARAM_OLD_BOOKMARK_PARENT = "old_bookmark_parent"; 54 public static final String PARAM_INSERT_IF_NEEDED = "insert_if_needed"; 55 public static final String PARAM_INCREMENT_VISITS = "increment_visits"; 56 public static final String PARAM_INCREMENT_REMOTE_AGGREGATES = "increment_remote_aggregates"; 57 public static final String PARAM_INCREMENT_LOCAL_VERSION_FROM_SYNC = "increment_local_version_from_sync"; 58 public static final String PARAM_RESET_VERSIONS_TO_SYNCED = "reset_versions_to_synced"; 59 public static final String PARAM_RESET_VERSIONS_FOR_ALL_TYPES = "reset_versions_for_all_types"; 60 public static final String PARAM_NON_POSITIONED_PINS = "non_positioned_pins"; 61 public static final String PARAM_EXPIRE_PRIORITY = "priority"; 62 public static final String PARAM_DATASET_ID = "dataset_id"; 63 public static final String PARAM_GROUP_BY = "group_by"; 64 65 public static final String METHOD_INSERT_HISTORY_WITH_VISITS_FROM_SYNC = "insertHistoryWithVisitsSync"; 66 public static final String METHOD_UPDATE_SYNC_VERSIONS = "updateSyncVersions"; 67 public static final String METHOD_RESET_RECORD_VERSIONS = "resetRecordVersions"; 68 public static final String METHOD_REPLACE_REMOTE_CLIENTS = "replaceRemoteClients"; 69 public static final String METHOD_UPDATE_BY_GUID_ASSERTING_LOCAL_VERSION = "updateByGuidAssertingLocalVersion"; 70 public static final String METHOD_RESULT = "methodResult"; 71 public static final String METHOD_PARAM_OBJECT = "object"; 72 public static final String METHOD_PARAM_DATA = "data"; 73 74 static public enum ExpirePriority { 75 NORMAL, 76 AGGRESSIVE 77 } 78 79 /** 80 * Produces a SQL expression used for sorting results of the "combined" view by frecency. 81 * Combines remote and local frecency calculations, weighting local visits much heavier. 82 * 83 * @param includesBookmarks When URL is bookmarked, should we give it bonus frecency points? 84 * @param ascending Indicates if sorting order ascending 85 * @return Combined frecency sorting expression 86 */ getCombinedFrecencySortOrder(boolean includesBookmarks, boolean ascending)87 static public String getCombinedFrecencySortOrder(boolean includesBookmarks, boolean ascending) { 88 final long now = System.currentTimeMillis(); 89 StringBuilder order = new StringBuilder(getRemoteFrecencySQL(now) + " + " + getLocalFrecencySQL(now)); 90 91 if (includesBookmarks) { 92 order.insert(0, "(CASE WHEN " + Combined.BOOKMARK_ID + " > -1 THEN 100 ELSE 0 END) + "); 93 } 94 95 order.append(ascending ? " ASC" : " DESC"); 96 return order.toString(); 97 } 98 99 /** 100 * See Bug 1265525 for details (explanation + graphs) on how Remote frecency compares to Local frecency for different 101 * combinations of visits count and age. 102 * 103 * @param now Base time in milliseconds for age calculation 104 * @return remote frecency SQL calculation 105 */ getRemoteFrecencySQL(final long now)106 static public String getRemoteFrecencySQL(final long now) { 107 return getFrecencyCalculation(now, 1, 110, Combined.REMOTE_VISITS_COUNT, Combined.REMOTE_DATE_LAST_VISITED); 108 } 109 110 /** 111 * Local frecency SQL calculation. Note higher scale factor and squared visit count which achieve 112 * visits generated locally being much preferred over remote visits. 113 * See Bug 1265525 for details (explanation + comparison graphs). 114 * 115 * @param now Base time in milliseconds for age calculation 116 * @return local frecency SQL calculation 117 */ getLocalFrecencySQL(final long now)118 static public String getLocalFrecencySQL(final long now) { 119 String visitCountExpr = "(" + Combined.LOCAL_VISITS_COUNT + " + 2)"; 120 visitCountExpr = visitCountExpr + " * " + visitCountExpr; 121 122 return getFrecencyCalculation(now, 2, 225, visitCountExpr, Combined.LOCAL_DATE_LAST_VISITED); 123 } 124 125 /** 126 * Our version of frecency is computed by scaling the number of visits by a multiplier 127 * that approximates Gaussian decay, based on how long ago the entry was last visited. 128 * Since we're limited by the math we can do with sqlite, we're calculating this 129 * approximation using the Cauchy distribution: multiplier = scale_const / (age^2 + scale_const). 130 * For example, with 15 as our scale parameter, we get a scale constant 15^2 = 225. Then: 131 * frecencyScore = numVisits * max(1, 100 * 225 / (age*age + 225)). (See bug 704977) 132 * 133 * @param now Base time in milliseconds for age calculation 134 * @param minFrecency Minimum allowed frecency value 135 * @param multiplier Scale constant 136 * @param visitCountExpr Expression which will produce a visit count 137 * @param lastVisitExpr Expression which will produce "last-visited" timestamp 138 * @return Frecency SQL calculation 139 */ getFrecencyCalculation(final long now, final int minFrecency, final int multiplier, @NonNull final String visitCountExpr, @NonNull final String lastVisitExpr)140 static public String getFrecencyCalculation(final long now, final int minFrecency, final int multiplier, @NonNull final String visitCountExpr, @NonNull final String lastVisitExpr) { 141 final long nowInMicroseconds = now * 1000; 142 final long microsecondsPerDay = 86400000000L; 143 final String ageExpr = "(" + nowInMicroseconds + " - " + lastVisitExpr + ") / " + microsecondsPerDay; 144 145 return visitCountExpr + " * MAX(" + minFrecency + ", 100 * " + multiplier + " / (" + ageExpr + " * " + ageExpr + " + " + multiplier + "))"; 146 } 147 148 @RobocopTarget 149 public interface CommonColumns { 150 public static final String _ID = "_id"; 151 } 152 153 @RobocopTarget 154 public interface DateSyncColumns { 155 public static final String DATE_CREATED = "created"; 156 public static final String DATE_MODIFIED = "modified"; 157 } 158 159 @RobocopTarget 160 public interface VersionColumns { 161 String LOCAL_VERSION = "localVersion"; 162 String SYNC_VERSION = "syncVersion"; 163 164 // This is a flag used to indicate that records inserted from sync should start as modified. 165 // That is, their versions will start as (2,1), instead of (1,1). 166 String PARAM_INSERT_FROM_SYNC_AS_MODIFIED = "modifiedBySync"; 167 } 168 169 @RobocopTarget 170 public interface SyncColumns extends DateSyncColumns { 171 public static final String GUID = "guid"; 172 public static final String IS_DELETED = "deleted"; 173 } 174 175 @RobocopTarget 176 public interface URLColumns { 177 public static final String URL = "url"; 178 public static final String TITLE = "title"; 179 } 180 181 @RobocopTarget 182 public interface FaviconColumns { 183 public static final String FAVICON = "favicon"; 184 public static final String FAVICON_ID = "favicon_id"; 185 public static final String FAVICON_URL = "favicon_url"; 186 } 187 188 @RobocopTarget 189 public interface HistoryColumns { 190 public static final String DATE_LAST_VISITED = "date"; 191 public static final String VISITS = "visits"; 192 // Aggregates used to speed up top sites and search frecency-powered queries 193 public static final String LOCAL_VISITS = "visits_local"; 194 public static final String REMOTE_VISITS = "visits_remote"; 195 public static final String LOCAL_DATE_LAST_VISITED = "date_local"; 196 public static final String REMOTE_DATE_LAST_VISITED = "date_remote"; 197 } 198 199 @RobocopTarget 200 public interface VisitsColumns { 201 public static final String HISTORY_GUID = "history_guid"; 202 public static final String VISIT_TYPE = "visit_type"; 203 public static final String DATE_VISITED = "date"; 204 // Used to distinguish between visits that were generated locally vs those that came in from Sync. 205 // Since we don't track "origin clientID" for visits, this is the best we can do for now. 206 public static final String IS_LOCAL = "is_local"; 207 } 208 209 public interface PageMetadataColumns { 210 public static final String HISTORY_GUID = "history_guid"; 211 public static final String DATE_CREATED = "created"; 212 public static final String HAS_IMAGE = "has_image"; 213 public static final String JSON = "json"; 214 } 215 216 public interface DeletedColumns { 217 public static final String ID = "id"; 218 public static final String GUID = "guid"; 219 public static final String TIME_DELETED = "timeDeleted"; 220 } 221 222 @RobocopTarget 223 public static final class Favicons implements CommonColumns, DateSyncColumns { Favicons()224 private Favicons() {} 225 226 public static final String TABLE_NAME = "favicons"; 227 228 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "favicons"); 229 230 public static final String URL = "url"; 231 public static final String DATA = "data"; 232 public static final String PAGE_URL = "page_url"; 233 } 234 235 @RobocopTarget 236 public static final class Thumbnails implements CommonColumns { Thumbnails()237 private Thumbnails() {} 238 239 public static final String TABLE_NAME = "thumbnails"; 240 241 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "thumbnails"); 242 243 public static final String URL = "url"; 244 public static final String DATA = "data"; 245 } 246 247 public static final class Profiles { Profiles()248 private Profiles() {} 249 public static final String NAME = "name"; 250 public static final String PATH = "path"; 251 } 252 253 @RobocopTarget 254 public static final class Bookmarks implements CommonColumns, URLColumns, FaviconColumns, SyncColumns, VersionColumns { Bookmarks()255 private Bookmarks() {} 256 257 public static final String TABLE_NAME = "bookmarks"; 258 259 public static final String VIEW_WITH_FAVICONS = "bookmarks_with_favicons"; 260 261 public static final String VIEW_WITH_ANNOTATIONS = "bookmarks_with_annotations"; 262 263 public static final int FIXED_ROOT_ID = 0; 264 public static final int FAKE_DESKTOP_FOLDER_ID = -1; 265 public static final int FIXED_READING_LIST_ID = -2; 266 public static final int FIXED_PINNED_LIST_ID = -3; 267 public static final int FIXED_SCREENSHOT_FOLDER_ID = -4; 268 public static final int FAKE_READINGLIST_SMARTFOLDER_ID = -5; 269 270 // Fixed position used by Activity Stream pins. A-S displays pins in front of other top sites, 271 // so position is constant for all pins. 272 public static final int FIXED_AS_PIN_POSITION = -1; 273 274 /** 275 * This ID and the following negative IDs are reserved for bookmarks from Android's partner 276 * bookmark provider. 277 */ 278 public static final long FAKE_PARTNER_BOOKMARKS_START = -1000; 279 280 public static final String MOBILE_FOLDER_GUID = "mobile"; 281 public static final String PLACES_FOLDER_GUID = "places"; 282 public static final String MENU_FOLDER_GUID = "menu"; 283 public static final String TAGS_FOLDER_GUID = "tags"; 284 public static final String TOOLBAR_FOLDER_GUID = "toolbar"; 285 public static final String UNFILED_FOLDER_GUID = "unfiled"; 286 public static final String FAKE_DESKTOP_FOLDER_GUID = "desktop"; 287 public static final String PINNED_FOLDER_GUID = "pinned"; 288 public static final String SCREENSHOT_FOLDER_GUID = "screenshots"; 289 public static final String FAKE_READINGLIST_SMARTFOLDER_GUID = "readinglist"; 290 291 public static final int TYPE_FOLDER = 0; 292 public static final int TYPE_BOOKMARK = 1; 293 public static final int TYPE_SEPARATOR = 2; 294 public static final int TYPE_LIVEMARK = 3; 295 public static final int TYPE_QUERY = 4; 296 297 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "bookmarks"); 298 public static final Uri PARENTS_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "parents"); 299 // Hacky API for bulk-updating positions. Bug 728783. 300 public static final Uri POSITIONS_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "positions"); 301 public static final long DEFAULT_POSITION = Long.MIN_VALUE; 302 303 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/bookmark"; 304 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/bookmark"; 305 public static final String TYPE = "type"; 306 public static final String PARENT = "parent"; 307 public static final String POSITION = "position"; 308 public static final String TAGS = "tags"; 309 public static final String DESCRIPTION = "description"; 310 public static final String KEYWORD = "keyword"; 311 312 public static final String ANNOTATION_KEY = "annotation_key"; 313 public static final String ANNOTATION_VALUE = "annotation_value"; 314 } 315 316 @RobocopTarget 317 public static final class History implements CommonColumns, URLColumns, HistoryColumns, FaviconColumns, SyncColumns { History()318 private History() {} 319 320 public static final String TABLE_NAME = "history"; 321 322 public static final String VIEW_WITH_FAVICONS = "history_with_favicons"; 323 324 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "history"); 325 public static final Uri CONTENT_OLD_URI = Uri.withAppendedPath(AUTHORITY_URI, "history/old"); 326 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/browser-history"; 327 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/browser-history"; 328 } 329 330 @RobocopTarget 331 public static final class Visits implements CommonColumns, VisitsColumns { Visits()332 private Visits() {} 333 334 public static final String TABLE_NAME = "visits"; 335 336 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "visits"); 337 338 public static final int VISIT_IS_LOCAL = 1; 339 public static final int VISIT_IS_REMOTE = 0; 340 } 341 342 // Combined bookmarks and history 343 @RobocopTarget 344 public static final class Combined implements CommonColumns, URLColumns, HistoryColumns, FaviconColumns { Combined()345 private Combined() {} 346 347 public static final String VIEW_NAME = "combined"; 348 349 public static final String VIEW_WITH_FAVICONS = "combined_with_favicons"; 350 351 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "combined"); 352 353 public static final String BOOKMARK_ID = "bookmark_id"; 354 public static final String HISTORY_ID = "history_id"; 355 public static final String HISTORY_GUID = "history_guid"; // sync GUID to merge with the PageMetadata table. 356 357 public static final String REMOTE_VISITS_COUNT = "remoteVisitCount"; 358 public static final String REMOTE_DATE_LAST_VISITED = "remoteDateLastVisited"; 359 360 public static final String LOCAL_VISITS_COUNT = "localVisitCount"; 361 public static final String LOCAL_DATE_LAST_VISITED = "localDateLastVisited"; 362 } 363 364 public static final class Schema { Schema()365 private Schema() {} 366 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "schema"); 367 368 public static final String VERSION = "version"; 369 } 370 371 public static final class Passwords { Passwords()372 private Passwords() {} 373 public static final Uri CONTENT_URI = Uri.withAppendedPath(PASSWORDS_AUTHORITY_URI, "passwords"); 374 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/passwords"; 375 376 public static final String ID = "id"; 377 public static final String HOSTNAME = "hostname"; 378 public static final String HTTP_REALM = "httpRealm"; 379 public static final String FORM_SUBMIT_URL = "formSubmitURL"; 380 public static final String USERNAME_FIELD = "usernameField"; 381 public static final String PASSWORD_FIELD = "passwordField"; 382 public static final String ENCRYPTED_USERNAME = "encryptedUsername"; 383 public static final String ENCRYPTED_PASSWORD = "encryptedPassword"; 384 public static final String ENC_TYPE = "encType"; 385 public static final String TIME_CREATED = "timeCreated"; 386 public static final String TIME_LAST_USED = "timeLastUsed"; 387 public static final String TIME_PASSWORD_CHANGED = "timePasswordChanged"; 388 public static final String TIMES_USED = "timesUsed"; 389 public static final String GUID = "guid"; 390 391 // This needs to be kept in sync with the types defined in toolkit/components/passwordmgr/nsILoginManagerCrypto.idl#45 392 public static final int ENCTYPE_SDR = 1; 393 } 394 395 public static final class DeletedPasswords implements DeletedColumns { DeletedPasswords()396 private DeletedPasswords() {} 397 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/deleted-passwords"; 398 public static final Uri CONTENT_URI = Uri.withAppendedPath(PASSWORDS_AUTHORITY_URI, "deleted-passwords"); 399 } 400 401 @RobocopTarget 402 public static final class GeckoDisabledHosts { GeckoDisabledHosts()403 private GeckoDisabledHosts() {} 404 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/disabled-hosts"; 405 public static final Uri CONTENT_URI = Uri.withAppendedPath(PASSWORDS_AUTHORITY_URI, "disabled-hosts"); 406 407 public static final String HOSTNAME = "hostname"; 408 } 409 410 public static final class FormHistory { FormHistory()411 private FormHistory() {} 412 public static final Uri CONTENT_URI = Uri.withAppendedPath(FORM_HISTORY_AUTHORITY_URI, "formhistory"); 413 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/formhistory"; 414 415 public static final String ID = "id"; 416 public static final String FIELD_NAME = "fieldname"; 417 public static final String VALUE = "value"; 418 public static final String TIMES_USED = "timesUsed"; 419 public static final String FIRST_USED = "firstUsed"; 420 public static final String LAST_USED = "lastUsed"; 421 public static final String GUID = "guid"; 422 } 423 424 public static final class DeletedFormHistory implements DeletedColumns { DeletedFormHistory()425 private DeletedFormHistory() {} 426 public static final Uri CONTENT_URI = Uri.withAppendedPath(FORM_HISTORY_AUTHORITY_URI, "deleted-formhistory"); 427 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/deleted-formhistory"; 428 } 429 430 @RobocopTarget 431 public static final class Tabs implements CommonColumns { Tabs()432 private Tabs() {} 433 public static final String TABLE_NAME = "tabs"; 434 435 public static final Uri CONTENT_URI = Uri.withAppendedPath(TABS_AUTHORITY_URI, "tabs"); 436 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/tab"; 437 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/tab"; 438 439 // Title of the tab. 440 public static final String TITLE = "title"; 441 442 // Topmost URL from the history array. Allows processing of this tab without 443 // parsing that array. 444 public static final String URL = "url"; 445 446 // Sync-assigned GUID for client device. NULL for local tabs. 447 public static final String CLIENT_GUID = "client_guid"; 448 449 // JSON-encoded array of history URL strings, from most recent to least recent. 450 public static final String HISTORY = "history"; 451 452 // Favicon URL for the tab's topmost history entry. 453 public static final String FAVICON = "favicon"; 454 455 // Last used time of the tab. 456 public static final String LAST_USED = "last_used"; 457 458 // Position of the tab. 0 represents foreground. 459 public static final String POSITION = "position"; 460 } 461 462 public static final class Clients implements CommonColumns { Clients()463 private Clients() {} 464 public static final Uri CONTENT_NO_STALE_SORTED_URI = Uri.withAppendedPath(TABS_AUTHORITY_URI, "clients_no_stale_sorted"); 465 public static final Uri CONTENT_URI = Uri.withAppendedPath(TABS_AUTHORITY_URI, "clients"); 466 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/client"; 467 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/client"; 468 469 // Client-provided name string. Could conceivably be null. 470 public static final String NAME = "name"; 471 472 // Sync-assigned GUID for client device. NULL for local tabs. 473 public static final String GUID = "guid"; 474 475 // Last modified time for the client's tab record. For remote records, a server 476 // timestamp provided by Sync during insertion. 477 public static final String LAST_MODIFIED = "last_modified"; 478 479 public static final String DEVICE_TYPE = "device_type"; 480 } 481 482 public static final class RemoteDevices implements CommonColumns, DateSyncColumns { RemoteDevices()483 private RemoteDevices() {} 484 public static final String TABLE_NAME = "remote_devices"; 485 486 public static final String GUID = "guid"; // FxA device ID 487 public static final String NAME = "name"; 488 public static final String TYPE = "type"; 489 public static final String IS_CURRENT_DEVICE = "is_current_device"; 490 public static final String LAST_ACCESS_TIME = "last_access_time"; 491 492 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "remote_devices"); 493 } 494 495 // Data storage for dynamic panels on about:home 496 @RobocopTarget 497 public static final class HomeItems implements CommonColumns { HomeItems()498 private HomeItems() {} 499 public static final Uri CONTENT_FAKE_URI = Uri.withAppendedPath(HOME_AUTHORITY_URI, "items/fake"); 500 public static final Uri CONTENT_URI = Uri.withAppendedPath(HOME_AUTHORITY_URI, "items"); 501 502 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/homeitem"; 503 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/homeitem"; 504 505 public static final String DATASET_ID = "dataset_id"; 506 public static final String URL = "url"; 507 public static final String TITLE = "title"; 508 public static final String DESCRIPTION = "description"; 509 public static final String IMAGE_URL = "image_url"; 510 public static final String BACKGROUND_COLOR = "background_color"; 511 public static final String BACKGROUND_URL = "background_url"; 512 public static final String CREATED = "created"; 513 public static final String FILTER = "filter"; 514 515 public static final String[] DEFAULT_PROJECTION = 516 new String[] { _ID, DATASET_ID, URL, TITLE, DESCRIPTION, IMAGE_URL, BACKGROUND_COLOR, BACKGROUND_URL, FILTER }; 517 } 518 519 @RobocopTarget 520 public static final class ReadingListItems implements CommonColumns, URLColumns { 521 public static final String EXCERPT = "excerpt"; 522 public static final String CLIENT_LAST_MODIFIED = "client_last_modified"; 523 public static final String GUID = "guid"; 524 public static final String SERVER_LAST_MODIFIED = "last_modified"; 525 public static final String SERVER_STORED_ON = "stored_on"; 526 public static final String ADDED_ON = "added_on"; 527 public static final String MARKED_READ_ON = "marked_read_on"; 528 public static final String IS_DELETED = "is_deleted"; 529 public static final String IS_ARCHIVED = "is_archived"; 530 public static final String IS_UNREAD = "is_unread"; 531 public static final String IS_ARTICLE = "is_article"; 532 public static final String IS_FAVORITE = "is_favorite"; 533 public static final String RESOLVED_URL = "resolved_url"; 534 public static final String RESOLVED_TITLE = "resolved_title"; 535 public static final String ADDED_BY = "added_by"; 536 public static final String MARKED_READ_BY = "marked_read_by"; 537 public static final String WORD_COUNT = "word_count"; 538 public static final String READ_POSITION = "read_position"; 539 public static final String CONTENT_STATUS = "content_status"; 540 541 public static final String SYNC_STATUS = "sync_status"; 542 public static final String SYNC_CHANGE_FLAGS = "sync_change_flags"; 543 ReadingListItems()544 private ReadingListItems() {} 545 public static final Uri CONTENT_URI = Uri.withAppendedPath(READING_LIST_AUTHORITY_URI, "items"); 546 547 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/readinglistitem"; 548 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/readinglistitem"; 549 550 // CONTENT_STATUS represents the result of an attempt to fetch content for the reading list item. 551 public static final int STATUS_UNFETCHED = 0; 552 public static final int STATUS_FETCH_FAILED_TEMPORARY = 1; 553 public static final int STATUS_FETCH_FAILED_PERMANENT = 2; 554 public static final int STATUS_FETCH_FAILED_UNSUPPORTED_FORMAT = 3; 555 public static final int STATUS_FETCHED_ARTICLE = 4; 556 557 // See https://github.com/mozilla-services/readinglist/wiki/Client-phases for how this is expected to work. 558 // 559 // If an item is SYNCED, it doesn't need to be uploaded. 560 // 561 // If its status is NEW, the entire record should be uploaded. 562 // 563 // If DELETED, the record should be deleted. A record can only move into this state from SYNCED; NEW records 564 // are deleted immediately. 565 // 566 567 public static final int SYNC_STATUS_SYNCED = 0; 568 public static final int SYNC_STATUS_NEW = 1; // Upload everything. 569 public static final int SYNC_STATUS_DELETED = 2; // Delete the record from the server. 570 public static final int SYNC_STATUS_MODIFIED = 3; // Consult SYNC_CHANGE_FLAGS. 571 572 // SYNC_CHANGE_FLAG represents the sets of fields that need to be uploaded. 573 // If its status is only UNREAD_CHANGED (and maybe FAVORITE_CHANGED?), then it can easily be uploaded 574 // in a fire-and-forget manner. This change can never conflict. 575 // 576 // If its status is RESOLVED, then one or more of the content-oriented fields has changed, and a full 577 // upload of those fields should occur. These can result in conflicts. 578 // 579 // Note that these are flags; they should be considered together when deciding on a course of action. 580 // 581 // These flags are meaningless for records in any state other than SYNCED. They can be safely altered in 582 // other states (to avoid having to query to pre-fill a ContentValues), but should be ignored. 583 public static final int SYNC_CHANGE_NONE = 0; 584 public static final int SYNC_CHANGE_UNREAD_CHANGED = 1 << 0; // => marked_read_{on,by}, is_unread 585 public static final int SYNC_CHANGE_FAVORITE_CHANGED = 1 << 1; // => is_favorite 586 public static final int SYNC_CHANGE_RESOLVED = 1 << 2; // => is_article, resolved_{url,title}, excerpt, word_count 587 588 589 public static final String DEFAULT_SORT_ORDER = CLIENT_LAST_MODIFIED + " DESC"; 590 public static final String[] DEFAULT_PROJECTION = new String[] { _ID, URL, TITLE, EXCERPT, WORD_COUNT, IS_UNREAD }; 591 592 // Minimum fields required to create a reading list item. 593 public static final String[] REQUIRED_FIELDS = { ReadingListItems.URL, ReadingListItems.TITLE }; 594 595 // All fields that might be mapped from the DB into a record object. 596 public static final String[] ALL_FIELDS = { 597 CommonColumns._ID, 598 URLColumns.URL, 599 URLColumns.TITLE, 600 EXCERPT, 601 CLIENT_LAST_MODIFIED, 602 GUID, 603 SERVER_LAST_MODIFIED, 604 SERVER_STORED_ON, 605 ADDED_ON, 606 MARKED_READ_ON, 607 IS_DELETED, 608 IS_ARCHIVED, 609 IS_UNREAD, 610 IS_ARTICLE, 611 IS_FAVORITE, 612 RESOLVED_URL, 613 RESOLVED_TITLE, 614 ADDED_BY, 615 MARKED_READ_BY, 616 WORD_COUNT, 617 READ_POSITION, 618 CONTENT_STATUS, 619 620 SYNC_STATUS, 621 SYNC_CHANGE_FLAGS, 622 }; 623 624 public static final String TABLE_NAME = "reading_list"; 625 } 626 627 @RobocopTarget 628 public static final class TopSites implements CommonColumns, URLColumns { TopSites()629 private TopSites() {} 630 631 public static final int TYPE_BLANK = 0; 632 public static final int TYPE_TOP = 1; 633 public static final int TYPE_PINNED = 2; 634 public static final int TYPE_SUGGESTED = 3; 635 636 @IntDef({TYPE_BLANK, TYPE_TOP, TYPE_PINNED, TYPE_SUGGESTED}) 637 public @interface TopSiteType {} 638 639 public static final String BOOKMARK_ID = "bookmark_id"; 640 public static final String HISTORY_ID = "history_id"; 641 public static final String TYPE = "type"; 642 public static final String PAGE_METADATA_JSON = "page_metadata_json"; 643 644 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "topsites"); 645 } 646 647 public static class Highlights { 648 public static final String BOOKMARK_ID = "bookmark_id"; 649 public static final String HISTORY_ID = "history_id"; 650 651 public static final String TITLE = "title"; 652 public static final String URL = "url"; 653 public static final String POSITION = "position"; 654 public static final String PARENT = "parent"; 655 public static final String DATE = "date"; 656 public static final String METADATA = "metadata"; 657 } 658 659 public static final class HighlightCandidates extends Highlights { 660 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "highlight_candidates"); 661 } 662 663 @RobocopTarget 664 public static final class SearchHistory implements CommonColumns, HistoryColumns { SearchHistory()665 private SearchHistory() {} 666 667 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/searchhistory"; 668 public static final String QUERY = "query"; 669 public static final String DATE = "date"; 670 public static final String TABLE_NAME = "searchhistory"; 671 672 public static final Uri CONTENT_URI = Uri.withAppendedPath(SEARCH_HISTORY_AUTHORITY_URI, "searchhistory"); 673 } 674 675 @RobocopTarget 676 public static final class SuggestedSites implements CommonColumns, URLColumns { SuggestedSites()677 private SuggestedSites() {} 678 679 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "suggestedsites"); 680 } 681 682 public static final class ActivityStreamBlocklist implements CommonColumns { ActivityStreamBlocklist()683 private ActivityStreamBlocklist() {} 684 685 public static final String TABLE_NAME = "activity_stream_blocklist"; 686 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, TABLE_NAME); 687 688 public static final String URL = "url"; 689 public static final String CREATED = "created"; 690 } 691 692 @RobocopTarget 693 public static final class UrlAnnotations implements CommonColumns, DateSyncColumns { UrlAnnotations()694 private UrlAnnotations() {} 695 696 public static final String TABLE_NAME = "urlannotations"; 697 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, TABLE_NAME); 698 699 public static final String URL = "url"; 700 public static final String KEY = "key"; 701 public static final String VALUE = "value"; 702 public static final String SYNC_STATUS = "sync_status"; 703 704 public enum Key { 705 // We use a parameter, rather than name(), as defensive coding: we can't let the 706 // enum name change because we've already stored values into the DB. 707 SCREENSHOT ("screenshot"), 708 709 /** 710 * This key maps URLs to its feeds. 711 * 712 * Key: feed 713 * Value: URL of feed 714 */ 715 FEED("feed"), 716 717 /** 718 * This key maps URLs of feeds to an object describing the feed. 719 * 720 * Key: feed_subscription 721 * Value: JSON object describing feed 722 */ 723 FEED_SUBSCRIPTION("feed_subscription"), 724 725 /** 726 * Indicates that this URL (if stored as a bookmark) should be opened into reader view. 727 * 728 * Key: reader_view 729 * Value: String "true" to indicate that we would like to open into reader view. 730 */ 731 READER_VIEW("reader_view"), 732 733 /** 734 * Indicator that the user interacted with the URL in regards to home screen shortcuts. 735 * 736 * Key: home_screen_shortcut 737 * Value: True: User created an home screen shortcut for this URL 738 * False: User declined to create a shortcut for this URL 739 */ 740 HOME_SCREEN_SHORTCUT("home_screen_shortcut"); 741 742 private final String dbValue; 743 Key(final String dbValue)744 Key(final String dbValue) { this.dbValue = dbValue; } getDbValue()745 public String getDbValue() { return dbValue; } 746 } 747 748 public enum SyncStatus { 749 // We use a parameter, rather than ordinal(), as defensive coding: we can't let the 750 // ordinal values change because we've already stored values into the DB. 751 NEW (0); 752 753 // Value stored into the database for this column. 754 private final int dbValue; 755 SyncStatus(final int dbValue)756 SyncStatus(final int dbValue) { 757 this.dbValue = dbValue; 758 } 759 getDBValue()760 public int getDBValue() { return dbValue; } 761 } 762 763 /** 764 * Value used to indicate that a reader view item is saved. We use the 765 */ 766 public static final String READER_VIEW_SAVED_VALUE = "true"; 767 } 768 769 public static final class Numbers { Numbers()770 private Numbers() {} 771 772 public static final String TABLE_NAME = "numbers"; 773 774 public static final String POSITION = "position"; 775 776 public static final int MAX_VALUE = 50; 777 } 778 779 @RobocopTarget 780 public static final class Logins implements CommonColumns { Logins()781 private Logins() {} 782 783 public static final Uri CONTENT_URI = Uri.withAppendedPath(LOGINS_AUTHORITY_URI, "logins"); 784 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/logins"; 785 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/logins"; 786 public static final String TABLE_LOGINS = "logins"; 787 788 public static final String HOSTNAME = "hostname"; 789 public static final String HTTP_REALM = "httpRealm"; 790 public static final String FORM_SUBMIT_URL = "formSubmitURL"; 791 public static final String USERNAME_FIELD = "usernameField"; 792 public static final String PASSWORD_FIELD = "passwordField"; 793 public static final String ENCRYPTED_USERNAME = "encryptedUsername"; 794 public static final String ENCRYPTED_PASSWORD = "encryptedPassword"; 795 public static final String ENC_TYPE = "encType"; 796 public static final String TIME_CREATED = "timeCreated"; 797 public static final String TIME_LAST_USED = "timeLastUsed"; 798 public static final String TIME_PASSWORD_CHANGED = "timePasswordChanged"; 799 public static final String TIMES_USED = "timesUsed"; 800 public static final String GUID = "guid"; 801 } 802 803 @RobocopTarget 804 public static final class DeletedLogins implements CommonColumns { DeletedLogins()805 private DeletedLogins() {} 806 807 public static final Uri CONTENT_URI = Uri.withAppendedPath(LOGINS_AUTHORITY_URI, "deleted-logins"); 808 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/deleted-logins"; 809 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/deleted-logins"; 810 public static final String TABLE_DELETED_LOGINS = "deleted_logins"; 811 812 public static final String GUID = "guid"; 813 public static final String TIME_DELETED = "timeDeleted"; 814 } 815 816 @RobocopTarget 817 public static final class LoginsDisabledHosts implements CommonColumns { LoginsDisabledHosts()818 private LoginsDisabledHosts() {} 819 820 public static final Uri CONTENT_URI = Uri.withAppendedPath(LOGINS_AUTHORITY_URI, "logins-disabled-hosts"); 821 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/logins-disabled-hosts"; 822 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/logins-disabled-hosts"; 823 public static final String TABLE_DISABLED_HOSTS = "logins_disabled_hosts"; 824 825 public static final String HOSTNAME = "hostname"; 826 } 827 828 @RobocopTarget 829 public static final class PageMetadata implements CommonColumns, PageMetadataColumns { PageMetadata()830 private PageMetadata() {} 831 832 public static final String TABLE_NAME = "page_metadata"; 833 public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "page_metadata"); 834 } 835 836 // We refer to the service by name to decouple services from the rest of the code base. 837 public static final String TAB_RECEIVED_SERVICE_CLASS_NAME = "org.mozilla.gecko.tabqueue.TabReceivedService"; 838 839 public static final String SKIP_TAB_QUEUE_FLAG = "skip_tab_queue"; 840 841 public static final String EXTRA_CLIENT_GUID = "org.mozilla.gecko.extra.CLIENT_ID"; 842 } 843