532c771d51e4c93d0b82ff6d6cc363e5b337f827
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / helpers / BookmarksDatabaseHelper.java
1 /*
2  * Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
6  * Privacy Browser is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.helpers;
21
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.database.Cursor;
25 import android.database.DatabaseUtils;
26 import android.database.sqlite.SQLiteDatabase;
27 import android.database.sqlite.SQLiteOpenHelper;
28
29 public class BookmarksDatabaseHelper extends SQLiteOpenHelper {
30     private static final int SCHEMA_VERSION = 1;
31     private static final String BOOKMARKS_DATABASE = "bookmarks.db";
32     private static final String BOOKMARKS_TABLE = "bookmarks";
33
34     public static final String _ID = "_id";
35     public static final String DISPLAY_ORDER = "displayorder";
36     public static final String BOOKMARK_NAME = "bookmarkname";
37     public static final String BOOKMARK_URL = "bookmarkurl";
38     public static final String PARENT_FOLDER = "parentfolder";
39     public static final String IS_FOLDER = "isfolder";
40     public static final String FAVORITE_ICON = "favoriteicon";
41
42     // Initialize the database.  The lint warnings for the unused parameters are suppressed.
43     public BookmarksDatabaseHelper(Context context, @SuppressWarnings("UnusedParameters") String name, SQLiteDatabase.CursorFactory cursorFactory, @SuppressWarnings("UnusedParameters") int version) {
44         super(context, BOOKMARKS_DATABASE, cursorFactory, SCHEMA_VERSION);
45     }
46
47     @Override
48     public void onCreate(SQLiteDatabase bookmarksDatabase) {
49         // Setup the SQL string to create the `bookmarks` table.
50         final String CREATE_BOOKMARKS_TABLE = "CREATE TABLE " + BOOKMARKS_TABLE + " (" +
51                 _ID + " integer primary key, " +
52                 DISPLAY_ORDER + " integer, " +
53                 BOOKMARK_NAME + " text, " +
54                 BOOKMARK_URL + " text, " +
55                 PARENT_FOLDER + " text, " +
56                 IS_FOLDER + " boolean, " +
57                 FAVORITE_ICON + " blob);";
58
59         // Create the `bookmarks` table.
60         bookmarksDatabase.execSQL(CREATE_BOOKMARKS_TABLE);
61     }
62
63     @Override
64     public void onUpgrade(SQLiteDatabase bookmarksDatabase, int oldVersion, int newVersion) {
65         // Code for upgrading the database will be added here when the schema version > 1.
66     }
67
68     // Create a bookmark.
69     public void createBookmark(String bookmarkName, String bookmarkURL, int displayOrder, String parentFolder, byte[] favoriteIcon) {
70         // We need to store the bookmark data in a `ContentValues`.
71         ContentValues bookmarkContentValues = new ContentValues();
72
73         // ID is created automatically.
74         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
75         bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
76         bookmarkContentValues.put(BOOKMARK_URL, bookmarkURL);
77         bookmarkContentValues.put(PARENT_FOLDER, parentFolder);
78         bookmarkContentValues.put(IS_FOLDER, false);
79         bookmarkContentValues.put(FAVORITE_ICON, favoriteIcon);
80
81         // Get a writable database handle.
82         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
83
84         // Insert a new row.  The second argument is `null`, which makes it so that a completely null row cannot be created.
85         bookmarksDatabase.insert(BOOKMARKS_TABLE, null, bookmarkContentValues);
86
87         // Close the database handle.
88         bookmarksDatabase.close();
89     }
90
91     // Create a folder.
92     public void createFolder(String folderName, int displayOrder, String parentFolder, byte[] favoriteIcon) {
93         ContentValues bookmarkContentValues = new ContentValues();
94
95         // ID is created automatically.
96         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
97         bookmarkContentValues.put(BOOKMARK_NAME, folderName);
98         bookmarkContentValues.put(PARENT_FOLDER, parentFolder);
99         bookmarkContentValues.put(IS_FOLDER, true);
100         bookmarkContentValues.put(FAVORITE_ICON, favoriteIcon);
101
102         // Get a writable database handle.
103         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
104
105         // The second argument is `null`, which makes it so that completely null rows cannot be created.  Not a problem in our case.
106         bookmarksDatabase.insert(BOOKMARKS_TABLE, null, bookmarkContentValues);
107
108         // Close the database handle.
109         bookmarksDatabase.close();
110     }
111
112     // Get a `Cursor` for the bookmark with the specified database ID.
113     public Cursor getBookmarkCursor(int databaseId) {
114         // Get a readable database handle.
115         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
116
117         // Prepare the SQL statement to get the `Cursor` for `databaseId`
118         final String GET_ONE_BOOKMARK = "SELECT * FROM " + BOOKMARKS_TABLE +
119                 " WHERE " + _ID + " = " + databaseId;
120
121         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.  We can't close the `Cursor` because we need to use it in the parent activity.
122         return bookmarksDatabase.rawQuery(GET_ONE_BOOKMARK, null);
123     }
124
125     // Get the folder name for the specified database ID.
126     public String getFolderName (int databaseId) {
127         // Get a readable database handle.
128         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
129
130         // Prepare the SQL statement to get the `Cursor` for the folder.
131         final String GET_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
132                 " WHERE " + _ID + " = " + databaseId;
133
134         // Get `folderCursor`.  The second argument is `null` because there are no `selectionArgs`.
135         Cursor folderCursor = bookmarksDatabase.rawQuery(GET_FOLDER, null);
136
137         // Get `folderName`.
138         folderCursor.moveToFirst();
139         String folderName = folderCursor.getString(folderCursor.getColumnIndex(BOOKMARK_NAME));
140
141         // Close the cursor and the database handle.
142         folderCursor.close();
143         bookmarksDatabase.close();
144
145         // Return the folder name.
146         return folderName;
147     }
148
149     // Get a `Cursor` for the specified folder name.
150     public Cursor getFolderCursor(String folderName) {
151         // Get a readable database handle.
152         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
153
154         // SQL escape `folderName`.
155         folderName = DatabaseUtils.sqlEscapeString(folderName);
156
157         // Prepare the SQL statement to get the `Cursor` for the folder.
158         final String GET_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
159                 " WHERE " + BOOKMARK_NAME + " = " + folderName +
160                 " AND " + IS_FOLDER + " = " + 1;
161
162         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
163         // We can't close the `Cursor` because we need to use it in the parent activity.
164         return bookmarksDatabase.rawQuery(GET_FOLDER, null);
165     }
166
167     // Get a `Cursor` of all the folders except those specified.
168     public Cursor getFoldersCursorExcept(String exceptFolders) {
169         // Get a readable database handle.
170         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
171
172         // Prepare the SQL statement to get the `Cursor` for the folders.
173         final String GET_FOLDERS_EXCEPT = "SELECT * FROM " + BOOKMARKS_TABLE +
174                 " WHERE " + IS_FOLDER + " = " + 1 +
175                 " AND " + BOOKMARK_NAME + " NOT IN (" + exceptFolders +
176                 ") ORDER BY " + BOOKMARK_NAME + " ASC";
177
178         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
179         // We can't close the `Cursor` because we need to use it in the parent activity.
180         return bookmarksDatabase.rawQuery(GET_FOLDERS_EXCEPT, null);
181     }
182
183     // Get a `Cursor` with all the subfolders of the specified folder.
184     public Cursor getSubfoldersCursor(String currentFolder) {
185         // Get a readable database handle.
186         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
187
188         // SQL escape `currentFolder.
189         currentFolder = DatabaseUtils.sqlEscapeString(currentFolder);
190
191         // Prepare the SQL statement to get the `Cursor` for the subfolders.
192         final String GET_SUBFOLDERS = "SELECT * FROM " + BOOKMARKS_TABLE +
193                 " WHERE " + PARENT_FOLDER + " = " + currentFolder +
194                 " AND " + IS_FOLDER + " = " + 1;
195
196         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
197         // We can't close the `Cursor` because we need to use it in the parent activity.
198         return bookmarksDatabase.rawQuery(GET_SUBFOLDERS, null);
199     }
200
201     // Get a `String` with the name of the parent folder.
202     public String getParentFolder(String currentFolder) {
203         // Get a readable database handle.
204         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
205
206         // SQL escape `currentFolder`.
207         currentFolder = DatabaseUtils.sqlEscapeString(currentFolder);
208
209         // Prepare the SQL statement to get the parent folder.
210         final String GET_PARENT_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
211                 " WHERE " + IS_FOLDER + " = " + 1 +
212                 " AND " + BOOKMARK_NAME + " = " + currentFolder;
213
214         // The second argument is `null` because there are no `selectionArgs`.
215         Cursor bookmarkCursor = bookmarksDatabase.rawQuery(GET_PARENT_FOLDER, null);
216         bookmarkCursor.moveToFirst();
217
218         // Store the name of the parent folder.
219         String parentFolder = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(PARENT_FOLDER));
220
221         // Close the `Cursor`.
222         bookmarkCursor.close();
223
224         return parentFolder;
225     }
226
227     // Get a `Cursor` of all the folders.
228     public Cursor getAllFoldersCursor() {
229         // Get a readable database handle.
230         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
231
232         // Prepare the SQL statement to get the `Cursor` for all the folders.
233         final String GET_ALL_FOLDERS = "SELECT * FROM " + BOOKMARKS_TABLE +
234                 " WHERE " + IS_FOLDER + " = " + 1 +
235                 " ORDER BY " + BOOKMARK_NAME + " ASC";
236
237         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
238         // We can't close the `Cursor` because we need to use it in the parent activity.
239         return bookmarksDatabase.rawQuery(GET_ALL_FOLDERS, null);
240     }
241
242     // Get a `Cursor` for all bookmarks and folders.
243     public Cursor getAllBookmarksCursor() {
244         // Get a readable database handle.
245         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
246
247         // Get everything in `BOOKMARKS_TABLE`.
248         final String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE;
249
250         // Return the results as a Cursor.  The second argument is `null` because there are no selectionArgs.
251         // We can't close the Cursor because we need to use it in the parent activity.
252         return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null);
253     }
254
255     // Get a `Cursor` for all bookmarks and folders in the specified folder.
256     public Cursor getAllBookmarksCursor(String folderName) {
257         // Get a readable database handle.
258         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
259
260         // SQL escape `folderName`.
261         folderName = DatabaseUtils.sqlEscapeString(folderName);
262
263         // Get everything in the `BOOKMARKS_TABLE` with `folderName` as the `PARENT_FOLDER`.
264         final String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE +
265                 " WHERE " + PARENT_FOLDER + " = " + folderName;
266
267         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.  We can't close the `Cursor` because we need to use it in the parent activity.
268         return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null);
269     }
270
271     // Get a `Cursor` for all bookmarks and folders in the specified folder ordered by display order.
272     public Cursor getAllBookmarksCursorByDisplayOrder(String folderName) {
273         // Get a readable database handle.
274         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
275
276         // SQL escape `folderName`.
277         folderName = DatabaseUtils.sqlEscapeString(folderName);
278
279         // Get everything in the `BOOKMARKS_TABLE` with `folderName` as the `PARENT_FOLDER`.
280         final String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE +
281                 " WHERE " + PARENT_FOLDER + " = " + folderName +
282                 " ORDER BY " + DISPLAY_ORDER + " ASC";
283
284         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.  We can't close the `Cursor` because we need to use it in the parent activity.
285         return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null);
286     }
287
288     // Get a `Cursor` for all bookmarks and folders in the specified folder except for a specific list of IDs.
289     public Cursor getBookmarksCursorExcept(long[] exceptIdLongArray, String folderName) {
290         // Get a readable database handle.
291         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
292
293         // Prepare a string that contains the comma-separated list of IDs not to get.
294         String doNotGetIdsString = "";
295         // Extract the array to `doNotGetIdsString`.
296         for (long databaseIdLong : exceptIdLongArray) {
297             // If this is the first number, only add the number.
298             if (doNotGetIdsString.isEmpty()) {
299                 doNotGetIdsString = String.valueOf(databaseIdLong);
300             } else {  // If there already is a number in the string, place a `,` before the number.
301                 doNotGetIdsString = doNotGetIdsString + "," + databaseIdLong;
302             }
303         }
304
305         // SQL escape `folderName`.
306         folderName = DatabaseUtils.sqlEscapeString(folderName);
307
308         // Prepare the SQL statement to select all items except those with the specified IDs.
309         final String GET_All_BOOKMARKS_EXCEPT_SPECIFIED = "SELECT * FROM " + BOOKMARKS_TABLE +
310                 " WHERE " + PARENT_FOLDER + " = " + folderName +
311                 " AND " + _ID + " NOT IN (" + doNotGetIdsString +
312                 ") ORDER BY " + DISPLAY_ORDER + " ASC";
313
314         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
315         // We can't close the `Cursor` because we need to use it in the parent activity.
316         return bookmarksDatabase.rawQuery(GET_All_BOOKMARKS_EXCEPT_SPECIFIED, null);
317     }
318
319     // Check if a database ID is a folder.
320     public boolean isFolder(int databaseId) {
321         // Get a readable database handle.
322         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
323
324         // Prepare the SQL statement to determine if `databaseId` is a folder.
325         final String CHECK_IF_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
326                 " WHERE " + _ID + " = " + databaseId;
327
328         // Populate folderCursor.  The second argument is `null` because there are no `selectionArgs`.
329         Cursor folderCursor = bookmarksDatabase.rawQuery(CHECK_IF_FOLDER, null);
330
331         // Ascertain if this database ID is a folder.
332         folderCursor.moveToFirst();
333         boolean isFolder = (folderCursor.getInt(folderCursor.getColumnIndex(IS_FOLDER)) == 1);
334
335         // Close the `Cursor` and the database handle.
336         folderCursor.close();
337         bookmarksDatabase.close();
338
339         return isFolder;
340     }
341
342     // Update the bookmark name and URL.
343     public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl) {
344         // Store the updated values in `bookmarkContentValues`.
345         ContentValues bookmarkContentValues = new ContentValues();
346
347         bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
348         bookmarkContentValues.put(BOOKMARK_URL, bookmarkUrl);
349
350         // Get a writable database handle.
351         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
352
353         // Update the bookmark.  The last argument is `null` because there are no `whereArgs`.
354         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
355
356         // Close the database handle.
357         bookmarksDatabase.close();
358     }
359
360     // Update the bookmark name, URL, and favorite icon.
361     public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl, byte[] favoriteIcon) {
362         // Store the updated values in `bookmarkContentValues`.
363         ContentValues bookmarkContentValues = new ContentValues();
364
365         bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
366         bookmarkContentValues.put(BOOKMARK_URL, bookmarkUrl);
367         bookmarkContentValues.put(FAVORITE_ICON, favoriteIcon);
368
369         // Get a writable database handle.
370         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
371
372         // Update the bookmark.  The last argument is `null` because there are no `whereArgs`.
373         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
374
375         // Close the database handle.
376         bookmarksDatabase.close();
377     }
378
379     // Update the folder name.
380     public void updateFolder(int databaseId, String oldFolderName, String newFolderName) {
381         // Get a writable database handle.
382         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
383
384         // Update the folder first.  Store the new folder name in `folderContentValues`.
385         ContentValues folderContentValues = new ContentValues();
386         folderContentValues.put(BOOKMARK_NAME, newFolderName);
387
388         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
389         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
390
391         // Update the bookmarks inside the folder.  Store the new parent folder name in `bookmarkContentValues`.
392         ContentValues bookmarkContentValues = new ContentValues();
393         bookmarkContentValues.put(PARENT_FOLDER, newFolderName);
394
395         // SQL escape `oldFolderName`.
396         oldFolderName = DatabaseUtils.sqlEscapeString(oldFolderName);
397
398         // Run the update on all the bookmarks that currently list `oldFolderName` as their parent folder.  The last argument is `null` because there are no `whereArgs`.
399         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, PARENT_FOLDER + " = " + oldFolderName, null);
400
401         // Close the database handle.
402         bookmarksDatabase.close();
403     }
404
405     // Update the folder icon.
406     public void updateFolder(int databaseId, byte[] folderIcon) {
407         // Get a writable database handle.
408         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
409
410         // Store the updated icon in `folderContentValues`.
411         ContentValues folderContentValues = new ContentValues();
412         folderContentValues.put(FAVORITE_ICON, folderIcon);
413
414         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
415         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
416
417         // Close the database handle.
418         bookmarksDatabase.close();
419     }
420
421     // Update the folder name and icon.
422     public void updateFolder(int databaseId, String oldFolderName, String newFolderName, byte[] folderIcon) {
423         // Get a writable database handle.
424         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
425
426         // Update the folder first.  Store the updated values in `folderContentValues`.
427         ContentValues folderContentValues = new ContentValues();
428         folderContentValues.put(BOOKMARK_NAME, newFolderName);
429         folderContentValues.put(FAVORITE_ICON, folderIcon);
430
431         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
432         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
433
434         // Update the bookmarks inside the folder.  Store the new parent folder name in `bookmarkContentValues`.
435         ContentValues bookmarkContentValues = new ContentValues();
436         bookmarkContentValues.put(PARENT_FOLDER, newFolderName);
437
438         // SQL escape `oldFolderName`.
439         oldFolderName = DatabaseUtils.sqlEscapeString(oldFolderName);
440
441         // Run the update on all the bookmarks that currently list `oldFolderName` as their parent folder.  The last argument is `null` because there are no `whereArgs`.
442         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, PARENT_FOLDER + " = " + oldFolderName, null);
443
444         // Close the database handle.
445         bookmarksDatabase.close();
446     }
447
448     // Update the display order for one bookmark or folder.
449     public void updateDisplayOrder(int databaseId, int displayOrder) {
450         // Get a writable database handle.
451         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
452
453         // Store the new display order in `bookmarkContentValues`.
454         ContentValues bookmarkContentValues = new ContentValues();
455         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
456
457         // Update the database.  The last argument is `null` because there are no `whereArgs`.
458         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
459
460         // Close the database handle.
461         bookmarksDatabase.close();
462     }
463
464     // Move one bookmark or folder to a new folder.
465     public void moveToFolder(int databaseId, String newFolder) {
466         // Get a writable database handle.
467         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
468
469         // SQL escape the new folder name.
470         String newFolderSqlEscaped = DatabaseUtils.sqlEscapeString(newFolder);
471
472         // Prepare a SQL query to select all the bookmarks in the new folder.
473         final String NEW_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
474                 " WHERE " + PARENT_FOLDER + " = " + newFolderSqlEscaped +
475                 " ORDER BY " + DISPLAY_ORDER + " ASC";
476
477         // Get a cursor for all the bookmarks in the new folder.  The second argument is `null` because there are no `selectionArgs`.
478         Cursor newFolderCursor = bookmarksDatabase.rawQuery(NEW_FOLDER, null);
479
480         // Instantiate a variable to store the display order after the move.
481         int displayOrder;
482
483         // Set the new display order.
484         if (newFolderCursor.getCount() > 0) {  // There are already bookmarks in the folder.
485             // Move to the last bookmark.
486             newFolderCursor.moveToLast();
487
488             // Set the display order to be one greater that the last bookmark.
489             displayOrder = newFolderCursor.getInt(newFolderCursor.getColumnIndex(DISPLAY_ORDER)) + 1;
490         } else {  // There are no bookmarks in the new folder.
491             // Set the display order to be `0`.
492             displayOrder = 0;
493         }
494
495         // Close the new folder `Cursor`.
496         newFolderCursor.close();
497
498         // Store the new values in `bookmarkContentValues`.
499         ContentValues bookmarkContentValues = new ContentValues();
500         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
501         bookmarkContentValues.put(PARENT_FOLDER, newFolder);
502
503         // Update the database.  The last argument is `null` because there are no `whereArgs`.
504         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
505
506         // Close the database handle.
507         bookmarksDatabase.close();
508     }
509
510     // Delete one bookmark.
511     public void deleteBookmark(int databaseId) {
512         // Get a writable database handle.
513         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
514
515         // Deletes the row with the given `databaseId`.  The last argument is `null` because we don't need additional parameters.
516         bookmarksDatabase.delete(BOOKMARKS_TABLE, _ID + " = " + databaseId, null);
517
518         // Close the database handle.
519         bookmarksDatabase.close();
520     }
521 }