Add editing functionality to the bookmarks database view. https://redmine.stoutner...
[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 BOOKMARK_NAME = "bookmarkname";
36     public static final String BOOKMARK_URL = "bookmarkurl";
37     public static final String PARENT_FOLDER = "parentfolder";
38     public static final String DISPLAY_ORDER = "displayorder";
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                 BOOKMARK_NAME + " text, " +
53                 BOOKMARK_URL + " text, " +
54                 PARENT_FOLDER + " text, " +
55                 DISPLAY_ORDER + " integer, " +
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, String parentFolder, int displayOrder, 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(BOOKMARK_NAME, bookmarkName);
75         bookmarkContentValues.put(BOOKMARK_URL, bookmarkURL);
76         bookmarkContentValues.put(PARENT_FOLDER, parentFolder);
77         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
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, String parentFolder, byte[] favoriteIcon) {
93         ContentValues bookmarkContentValues = new ContentValues();
94
95         // ID is created automatically.  Folders are always created at the top of the list.
96         bookmarkContentValues.put(BOOKMARK_NAME, folderName);
97         bookmarkContentValues.put(PARENT_FOLDER, parentFolder);
98         bookmarkContentValues.put(DISPLAY_ORDER, 0);
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     // The the database ID for the specified folder name.
150     public int getFolderDatabaseId (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         // Get `folderCursor`.  The second argument is `null` because there are no `selectionArgs`.
163         Cursor folderCursor = bookmarksDatabase.rawQuery(GET_FOLDER, null);
164
165         // Get the database ID.
166         folderCursor.moveToFirst();
167         int databaseId = folderCursor.getInt(folderCursor.getColumnIndex(_ID));
168
169         // Close the cursor and the database handle.
170         folderCursor.close();
171         bookmarksDatabase.close();
172
173         // Return the database ID.
174         return databaseId;
175     }
176
177     // Get a `Cursor` for the specified folder name.
178     public Cursor getFolderCursor(String folderName) {
179         // Get a readable database handle.
180         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
181
182         // SQL escape `folderName`.
183         folderName = DatabaseUtils.sqlEscapeString(folderName);
184
185         // Prepare the SQL statement to get the `Cursor` for the folder.
186         final String GET_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
187                 " WHERE " + BOOKMARK_NAME + " = " + folderName +
188                 " AND " + IS_FOLDER + " = " + 1;
189
190         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
191         // We can't close the `Cursor` because we need to use it in the parent activity.
192         return bookmarksDatabase.rawQuery(GET_FOLDER, null);
193     }
194
195     // Get a `Cursor` of all the folders except those specified.
196     public Cursor getFoldersCursorExcept(String exceptFolders) {
197         // Get a readable database handle.
198         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
199
200         // Prepare the SQL statement to get the `Cursor` for the folders.
201         final String GET_FOLDERS_EXCEPT = "SELECT * FROM " + BOOKMARKS_TABLE +
202                 " WHERE " + IS_FOLDER + " = " + 1 +
203                 " AND " + BOOKMARK_NAME + " NOT IN (" + exceptFolders +
204                 ") ORDER BY " + BOOKMARK_NAME + " ASC";
205
206         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
207         // We can't close the `Cursor` because we need to use it in the parent activity.
208         return bookmarksDatabase.rawQuery(GET_FOLDERS_EXCEPT, null);
209     }
210
211     // Get a `Cursor` with all the subfolders of the specified folder.
212     public Cursor getSubfoldersCursor(String currentFolder) {
213         // Get a readable database handle.
214         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
215
216         // SQL escape `currentFolder.
217         currentFolder = DatabaseUtils.sqlEscapeString(currentFolder);
218
219         // Prepare the SQL statement to get the `Cursor` for the subfolders.
220         final String GET_SUBFOLDERS = "SELECT * FROM " + BOOKMARKS_TABLE +
221                 " WHERE " + PARENT_FOLDER + " = " + currentFolder +
222                 " AND " + IS_FOLDER + " = " + 1;
223
224         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
225         // We can't close the `Cursor` because we need to use it in the parent activity.
226         return bookmarksDatabase.rawQuery(GET_SUBFOLDERS, null);
227     }
228
229     // Get a `String` with the name of the parent folder.
230     public String getParentFolder(String currentFolder) {
231         // Get a readable database handle.
232         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
233
234         // SQL escape `currentFolder`.
235         currentFolder = DatabaseUtils.sqlEscapeString(currentFolder);
236
237         // Prepare the SQL statement to get the parent folder.
238         final String GET_PARENT_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
239                 " WHERE " + IS_FOLDER + " = " + 1 +
240                 " AND " + BOOKMARK_NAME + " = " + currentFolder;
241
242         // The second argument is `null` because there are no `selectionArgs`.
243         Cursor bookmarkCursor = bookmarksDatabase.rawQuery(GET_PARENT_FOLDER, null);
244         bookmarkCursor.moveToFirst();
245
246         // Store the name of the parent folder.
247         String parentFolder = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(PARENT_FOLDER));
248
249         // Close the `Cursor`.
250         bookmarkCursor.close();
251
252         return parentFolder;
253     }
254
255     // Get a `Cursor` of all the folders.
256     public Cursor getAllFoldersCursor() {
257         // Get a readable database handle.
258         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
259
260         // Prepare the SQL statement to get the `Cursor` for all the folders.
261         final String GET_ALL_FOLDERS = "SELECT * FROM " + BOOKMARKS_TABLE +
262                 " WHERE " + IS_FOLDER + " = " + 1 +
263                 " ORDER BY " + BOOKMARK_NAME + " ASC";
264
265         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
266         // We can't close the `Cursor` because we need to use it in the parent activity.
267         return bookmarksDatabase.rawQuery(GET_ALL_FOLDERS, null);
268     }
269
270     // Get a `Cursor` for all bookmarks and folders.
271     public Cursor getAllBookmarksCursor() {
272         // Get a readable database handle.
273         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
274
275         // Get everything in `BOOKMARKS_TABLE`.
276         final String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE;
277
278         // Return the results as a Cursor.  The second argument is `null` because there are no selectionArgs.
279         // We can't close the Cursor because we need to use it in the parent activity.
280         return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null);
281     }
282
283     // Get a `Cursor` for all bookmarks and folders in the specified folder.
284     public Cursor getAllBookmarksCursor(String folderName) {
285         // Get a readable database handle.
286         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
287
288         // SQL escape `folderName`.
289         folderName = DatabaseUtils.sqlEscapeString(folderName);
290
291         // Get everything in the `BOOKMARKS_TABLE` with `folderName` as the `PARENT_FOLDER`.
292         final String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE +
293                 " WHERE " + PARENT_FOLDER + " = " + folderName;
294
295         // 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.
296         return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null);
297     }
298
299     // Get a `Cursor` for all bookmarks and folders in the specified folder ordered by display order.
300     public Cursor getAllBookmarksCursorByDisplayOrder(String folderName) {
301         // Get a readable database handle.
302         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
303
304         // SQL escape `folderName`.
305         folderName = DatabaseUtils.sqlEscapeString(folderName);
306
307         // Get everything in the `BOOKMARKS_TABLE` with `folderName` as the `PARENT_FOLDER`.
308         final String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE +
309                 " WHERE " + PARENT_FOLDER + " = " + folderName +
310                 " ORDER BY " + DISPLAY_ORDER + " ASC";
311
312         // 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.
313         return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null);
314     }
315
316     // Get a `Cursor` for all bookmarks and folders in the specified folder except for a specific list of IDs.
317     public Cursor getBookmarksCursorExcept(long[] exceptIdLongArray, String folderName) {
318         // Get a readable database handle.
319         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
320
321         // Prepare a string builder that contains the comma-separated list of IDs not to get.
322         StringBuilder doNotGetIdsStringBuilder = new StringBuilder();
323
324         // Extract the array to `doNotGetIdsString`.
325         for (long databaseIdLong : exceptIdLongArray) {
326             // If this is the first number, only add the number.
327             if (doNotGetIdsStringBuilder.toString().isEmpty()) {
328                 doNotGetIdsStringBuilder.append(databaseIdLong);
329             } else {  // If there already is a number in the string, place a `,` before the new number.
330                 doNotGetIdsStringBuilder.append(",");
331                 doNotGetIdsStringBuilder.append(databaseIdLong);
332             }
333         }
334
335         // SQL escape `folderName`.
336         folderName = DatabaseUtils.sqlEscapeString(folderName);
337
338         // Prepare the SQL statement to select all items except those with the specified IDs.
339         final String GET_All_BOOKMARKS_EXCEPT_SPECIFIED = "SELECT * FROM " + BOOKMARKS_TABLE +
340                 " WHERE " + PARENT_FOLDER + " = " + folderName +
341                 " AND " + _ID + " NOT IN (" + doNotGetIdsStringBuilder.toString() +
342                 ") ORDER BY " + DISPLAY_ORDER + " ASC";
343
344         // Return the results as a `Cursor`.  The second argument is `null` because there are no `selectionArgs`.
345         // We can't close the `Cursor` because we need to use it in the parent activity.
346         return bookmarksDatabase.rawQuery(GET_All_BOOKMARKS_EXCEPT_SPECIFIED, null);
347     }
348
349     // Check if a database ID is a folder.
350     public boolean isFolder(int databaseId) {
351         // Get a readable database handle.
352         SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
353
354         // Prepare the SQL statement to determine if `databaseId` is a folder.
355         final String CHECK_IF_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
356                 " WHERE " + _ID + " = " + databaseId;
357
358         // Populate folderCursor.  The second argument is `null` because there are no `selectionArgs`.
359         Cursor folderCursor = bookmarksDatabase.rawQuery(CHECK_IF_FOLDER, null);
360
361         // Ascertain if this database ID is a folder.
362         folderCursor.moveToFirst();
363         boolean isFolder = (folderCursor.getInt(folderCursor.getColumnIndex(IS_FOLDER)) == 1);
364
365         // Close the `Cursor` and the database handle.
366         folderCursor.close();
367         bookmarksDatabase.close();
368
369         return isFolder;
370     }
371
372     // Update the bookmark name and URL.
373     public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl) {
374         // Initialize a `ContentValues`.
375         ContentValues bookmarkContentValues = new ContentValues();
376
377         // Store the updated values.
378         bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
379         bookmarkContentValues.put(BOOKMARK_URL, bookmarkUrl);
380
381         // Get a writable database handle.
382         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
383
384         // Update the bookmark.  The last argument is `null` because there are no `whereArgs`.
385         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
386
387         // Close the database handle.
388         bookmarksDatabase.close();
389     }
390
391     // Update the bookmark name, URL, parent folder, and display order.
392     public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl, String parentFolder, int displayOrder) {
393         // Initialize a `ContentValues`.
394         ContentValues bookmarkContentValues = new ContentValues();
395
396         // Store the updated values.
397         bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
398         bookmarkContentValues.put(BOOKMARK_URL, bookmarkUrl);
399         bookmarkContentValues.put(PARENT_FOLDER, parentFolder);
400         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
401
402         // Get a writable database handle.
403         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
404
405         // Update the bookmark.  The last argument is `null` because there are no `whereArgs`.
406         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
407
408         // Close the database handle.
409         bookmarksDatabase.close();
410     }
411
412     // Update the bookmark name, URL, and favorite icon.
413     public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl, byte[] favoriteIcon) {
414         // Initialize a `ContentValues`.
415         ContentValues bookmarkContentValues = new ContentValues();
416
417         // Store the updated values.
418         bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
419         bookmarkContentValues.put(BOOKMARK_URL, bookmarkUrl);
420         bookmarkContentValues.put(FAVORITE_ICON, favoriteIcon);
421
422         // Get a writable database handle.
423         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
424
425         // Update the bookmark.  The last argument is `null` because there are no `whereArgs`.
426         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
427
428         // Close the database handle.
429         bookmarksDatabase.close();
430     }
431
432     // Update the bookmark name, URL, parent folder, display order, and favorite icon.
433     public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl, String parentFolder, int displayOrder, byte[] favoriteIcon) {
434         // Initialize a `ContentValues`.
435         ContentValues bookmarkContentValues = new ContentValues();
436
437         // Store the updated values.
438         bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName);
439         bookmarkContentValues.put(BOOKMARK_URL, bookmarkUrl);
440         bookmarkContentValues.put(PARENT_FOLDER, parentFolder);
441         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
442         bookmarkContentValues.put(FAVORITE_ICON, favoriteIcon);
443
444         // Get a writable database handle.
445         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
446
447         // Update the bookmark.  The last argument is `null` because there are no `whereArgs`.
448         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
449
450         // Close the database handle.
451         bookmarksDatabase.close();
452     }
453
454     // Update the folder name.
455     public void updateFolder(int databaseId, String oldFolderName, String newFolderName) {
456         // Get a writable database handle.
457         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
458
459         // Update the folder first.  Store the new folder name in `folderContentValues`.
460         ContentValues folderContentValues = new ContentValues();
461         folderContentValues.put(BOOKMARK_NAME, newFolderName);
462
463         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
464         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
465
466         // Update the bookmarks inside the folder.  Store the new parent folder name in `bookmarkContentValues`.
467         ContentValues bookmarkContentValues = new ContentValues();
468         bookmarkContentValues.put(PARENT_FOLDER, newFolderName);
469
470         // SQL escape `oldFolderName`.
471         oldFolderName = DatabaseUtils.sqlEscapeString(oldFolderName);
472
473         // 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`.
474         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, PARENT_FOLDER + " = " + oldFolderName, null);
475
476         // Close the database handle.
477         bookmarksDatabase.close();
478     }
479
480     // Update the folder icon.
481     public void updateFolder(int databaseId, byte[] folderIcon) {
482         // Get a writable database handle.
483         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
484
485         // Store the updated icon in `folderContentValues`.
486         ContentValues folderContentValues = new ContentValues();
487         folderContentValues.put(FAVORITE_ICON, folderIcon);
488
489         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
490         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
491
492         // Close the database handle.
493         bookmarksDatabase.close();
494     }
495
496     // Update the folder name, parent folder, and display order.
497     public void updateFolder(int databaseId, String oldFolderName, String newFolderName, String parentFolder, int displayOrder) {
498         // Get a writable database handle.
499         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
500
501         // Update the folder first.  Store the new folder name in `folderContentValues`.
502         ContentValues folderContentValues = new ContentValues();
503         folderContentValues.put(BOOKMARK_NAME, newFolderName);
504         folderContentValues.put(PARENT_FOLDER, parentFolder);
505         folderContentValues.put(DISPLAY_ORDER, displayOrder);
506
507         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
508         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
509
510         // Update the bookmarks inside the folder.  Store the new parent folder name in `bookmarkContentValues`.
511         ContentValues bookmarkContentValues = new ContentValues();
512         bookmarkContentValues.put(PARENT_FOLDER, newFolderName);
513
514         // SQL escape `oldFolderName`.
515         oldFolderName = DatabaseUtils.sqlEscapeString(oldFolderName);
516
517         // 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`.
518         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, PARENT_FOLDER + " = " + oldFolderName, null);
519
520         // Close the database handle.
521         bookmarksDatabase.close();
522     }
523
524     // Update the folder name and icon.
525     public void updateFolder(int databaseId, String oldFolderName, String newFolderName, byte[] folderIcon) {
526         // Get a writable database handle.
527         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
528
529         // Update the folder first.  Store the updated values in `folderContentValues`.
530         ContentValues folderContentValues = new ContentValues();
531         folderContentValues.put(BOOKMARK_NAME, newFolderName);
532         folderContentValues.put(FAVORITE_ICON, folderIcon);
533
534         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
535         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
536
537         // Update the bookmarks inside the folder.  Store the new parent folder name in `bookmarkContentValues`.
538         ContentValues bookmarkContentValues = new ContentValues();
539         bookmarkContentValues.put(PARENT_FOLDER, newFolderName);
540
541         // SQL escape `oldFolderName`.
542         oldFolderName = DatabaseUtils.sqlEscapeString(oldFolderName);
543
544         // 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`.
545         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, PARENT_FOLDER + " = " + oldFolderName, null);
546
547         // Close the database handle.
548         bookmarksDatabase.close();
549     }
550
551     // Update the folder name and icon.
552     public void updateFolder(int databaseId, String oldFolderName, String newFolderName, String parentFolder, int displayOrder, byte[] folderIcon) {
553         // Get a writable database handle.
554         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
555
556         // Update the folder first.  Store the updated values in `folderContentValues`.
557         ContentValues folderContentValues = new ContentValues();
558         folderContentValues.put(BOOKMARK_NAME, newFolderName);
559         folderContentValues.put(PARENT_FOLDER, parentFolder);
560         folderContentValues.put(DISPLAY_ORDER, displayOrder);
561         folderContentValues.put(FAVORITE_ICON, folderIcon);
562
563         // Run the update on the folder.  The last argument is `null` because there are no `whereArgs`.
564         bookmarksDatabase.update(BOOKMARKS_TABLE, folderContentValues, _ID + " = " + databaseId, null);
565
566         // Update the bookmarks inside the folder.  Store the new parent folder name in `bookmarkContentValues`.
567         ContentValues bookmarkContentValues = new ContentValues();
568         bookmarkContentValues.put(PARENT_FOLDER, newFolderName);
569
570         // SQL escape `oldFolderName`.
571         oldFolderName = DatabaseUtils.sqlEscapeString(oldFolderName);
572
573         // 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`.
574         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, PARENT_FOLDER + " = " + oldFolderName, null);
575
576         // Close the database handle.
577         bookmarksDatabase.close();
578     }
579
580     // Update the display order for one bookmark or folder.
581     public void updateDisplayOrder(int databaseId, int displayOrder) {
582         // Get a writable database handle.
583         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
584
585         // Store the new display order in `bookmarkContentValues`.
586         ContentValues bookmarkContentValues = new ContentValues();
587         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
588
589         // Update the database.  The last argument is `null` because there are no `whereArgs`.
590         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
591
592         // Close the database handle.
593         bookmarksDatabase.close();
594     }
595
596     // Move one bookmark or folder to a new folder.
597     public void moveToFolder(int databaseId, String newFolder) {
598         // Get a writable database handle.
599         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
600
601         // SQL escape the new folder name.
602         String newFolderSqlEscaped = DatabaseUtils.sqlEscapeString(newFolder);
603
604         // Prepare a SQL query to select all the bookmarks in the new folder.
605         final String NEW_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE +
606                 " WHERE " + PARENT_FOLDER + " = " + newFolderSqlEscaped +
607                 " ORDER BY " + DISPLAY_ORDER + " ASC";
608
609         // Get a cursor for all the bookmarks in the new folder.  The second argument is `null` because there are no `selectionArgs`.
610         Cursor newFolderCursor = bookmarksDatabase.rawQuery(NEW_FOLDER, null);
611
612         // Instantiate a variable to store the display order after the move.
613         int displayOrder;
614
615         // Set the new display order.
616         if (newFolderCursor.getCount() > 0) {  // There are already bookmarks in the folder.
617             // Move to the last bookmark.
618             newFolderCursor.moveToLast();
619
620             // Set the display order to be one greater that the last bookmark.
621             displayOrder = newFolderCursor.getInt(newFolderCursor.getColumnIndex(DISPLAY_ORDER)) + 1;
622         } else {  // There are no bookmarks in the new folder.
623             // Set the display order to be `0`.
624             displayOrder = 0;
625         }
626
627         // Close the new folder `Cursor`.
628         newFolderCursor.close();
629
630         // Store the new values in `bookmarkContentValues`.
631         ContentValues bookmarkContentValues = new ContentValues();
632         bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
633         bookmarkContentValues.put(PARENT_FOLDER, newFolder);
634
635         // Update the database.  The last argument is `null` because there are no `whereArgs`.
636         bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
637
638         // Close the database handle.
639         bookmarksDatabase.close();
640     }
641
642     // Delete one bookmark.
643     public void deleteBookmark(int databaseId) {
644         // Get a writable database handle.
645         SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
646
647         // Deletes the row with the given `databaseId`.  The last argument is `null` because we don't need additional parameters.
648         bookmarksDatabase.delete(BOOKMARKS_TABLE, _ID + " = " + databaseId, null);
649
650         // Close the database handle.
651         bookmarksDatabase.close();
652     }
653 }