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