]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt
Change the domain settings switches to spinners. https://redmine.stoutner.com/issues/407
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / helpers / DomainsDatabaseHelper.kt
1 /*
2  * Copyright © 2017-2023 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
6  * Privacy Browser Android 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 Android 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 Android.  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 import androidx.preference.PreferenceManager
30
31 import com.stoutner.privacybrowser.R
32
33 // Define the class constants.
34 private const val SCHEMA_VERSION = 16
35
36 // Define the public database constants.
37 const val DOMAINS_DATABASE = "domains.db"
38 const val DOMAINS_TABLE = "domains"
39
40 // Define the public spinner constants.
41 const val SYSTEM_DEFAULT = 0
42 const val ENABLED = 1
43 const val DISABLED = 2
44 const val LIGHT_THEME = 1
45 const val DARK_THEME = 2
46
47 // Define the public schema constants.
48 const val BLOCK_ALL_THIRD_PARTY_REQUESTS = "blockallthirdpartyrequests"
49 const val COOKIES = "cookies"
50 const val DISPLAY_IMAGES = "displayimages"
51 const val DOMAIN_NAME = "domainname"
52 const val ENABLE_DOM_STORAGE = "enabledomstorage"
53 const val ENABLE_EASYLIST = "enableeasylist"
54 const val ENABLE_EASYPRIVACY = "enableeasyprivacy"
55 const val ENABLE_FANBOYS_ANNOYANCE_LIST = "enablefanboysannoyancelist"
56 const val ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST = "enablefanboyssocialblockinglist"
57 const val ENABLE_FORM_DATA = "enableformdata" // Form data can be removed once the minimum API >= 26.
58 const val ENABLE_JAVASCRIPT = "enablejavascript"
59 const val ENABLE_ULTRAPRIVACY = "enableultraprivacy"
60 const val FONT_SIZE = "fontsize"
61 const val ID = "_id"
62 const val IP_ADDRESSES = "ip_addresses"
63 const val PINNED_IP_ADDRESSES = "pinned_ip_addresses"
64 const val PINNED_SSL_CERTIFICATE = "pinnedsslcertificate"
65 const val SSL_END_DATE = "sslenddate"
66 const val SSL_START_DATE = "sslstartdate"
67 const val SSL_ISSUED_BY_COMMON_NAME = "sslissuedbycommonname"
68 const val SSL_ISSUED_BY_ORGANIZATION = "sslissuedbyorganization"
69 const val SSL_ISSUED_BY_ORGANIZATIONAL_UNIT = "sslissuedbyorganizationalunit"
70 const val SSL_ISSUED_TO_COMMON_NAME = "sslissuedtocommonname"
71 const val SSL_ISSUED_TO_ORGANIZATION = "sslissuedtoorganization"
72 const val SSL_ISSUED_TO_ORGANIZATIONAL_UNIT = "sslissuedtoorganizationalunit"
73 const val SWIPE_TO_REFRESH = "swipetorefresh"
74 const val ULTRALIST = "ultralist"
75 const val USER_AGENT = "useragent"
76 const val WEBVIEW_THEME = "webview_theme"
77 const val WIDE_VIEWPORT = "wide_viewport"
78
79 // Define the public table creation constant.
80 const val CREATE_DOMAINS_TABLE = "CREATE TABLE $DOMAINS_TABLE (" +
81         "$ID INTEGER PRIMARY KEY, " +
82         "$DOMAIN_NAME TEXT, " +
83         "$ENABLE_JAVASCRIPT INTEGER, " +
84         "$COOKIES INTEGER, " +
85         "$ENABLE_DOM_STORAGE INTEGER, " +
86         "$ENABLE_FORM_DATA INTEGER, " +
87         "$ENABLE_EASYLIST INTEGER, " +
88         "$ENABLE_EASYPRIVACY INTEGER, " +
89         "$ENABLE_FANBOYS_ANNOYANCE_LIST INTEGER, " +
90         "$ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST INTEGER, " +
91         "$ULTRALIST INTEGER, " +
92         "$ENABLE_ULTRAPRIVACY INTEGER, " +
93         "$BLOCK_ALL_THIRD_PARTY_REQUESTS INTEGER, " +
94         "$USER_AGENT TEXT, " +
95         "$FONT_SIZE INTEGER, " +
96         "$SWIPE_TO_REFRESH INTEGER, " +
97         "$WEBVIEW_THEME INTEGER, " +
98         "$WIDE_VIEWPORT INTEGER, " +
99         "$DISPLAY_IMAGES INTEGER, " +
100         "$PINNED_SSL_CERTIFICATE BOOLEAN, " +
101         "$SSL_ISSUED_TO_COMMON_NAME TEXT, " +
102         "$SSL_ISSUED_TO_ORGANIZATION TEXT, " +
103         "$SSL_ISSUED_TO_ORGANIZATIONAL_UNIT TEXT, " +
104         "$SSL_ISSUED_BY_COMMON_NAME TEXT, " +
105         "$SSL_ISSUED_BY_ORGANIZATION TEXT, " +
106         "$SSL_ISSUED_BY_ORGANIZATIONAL_UNIT TEXT, " +
107         "$SSL_START_DATE INTEGER, " +
108         "$SSL_END_DATE INTEGER, " +
109         "$PINNED_IP_ADDRESSES BOOLEAN, " +
110         "$IP_ADDRESSES TEXT)"
111
112 class DomainsDatabaseHelper(private val appContext: Context) : SQLiteOpenHelper(appContext, DOMAINS_DATABASE, null, SCHEMA_VERSION) {
113     override fun onCreate(domainsDatabase: SQLiteDatabase) {
114         // Create the domains table.
115         domainsDatabase.execSQL(CREATE_DOMAINS_TABLE)
116     }
117
118     override fun onUpgrade(domainsDatabase: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
119         // Get a handle for the shared preference.
120         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(appContext)
121
122         // Upgrade from schema version 1, first used in Privacy Browser 2.0, to schema version 2, first used in Privacy Browser 2.3.
123         if (oldVersion < 2) {
124             // Add the display images column.
125             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $DISPLAY_IMAGES INTEGER")
126         }
127
128         // Upgrade from schema version 2, first used in Privacy Browser 2.3, to schema version 3, first used in Privacy Browser 2.5.
129         if (oldVersion < 3) {
130             //  Add the SSL certificate columns.
131             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $PINNED_SSL_CERTIFICATE BOOLEAN")
132             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_ISSUED_TO_COMMON_NAME TEXT")
133             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_ISSUED_TO_ORGANIZATION TEXT")
134             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_ISSUED_TO_ORGANIZATIONAL_UNIT TEXT")
135             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_ISSUED_BY_COMMON_NAME TEXT")
136             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_ISSUED_BY_ORGANIZATION TEXT")
137             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_ISSUED_BY_ORGANIZATIONAL_UNIT TEXT")
138             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_START_DATE INTEGER")
139             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SSL_END_DATE INTEGER")
140         }
141
142         // Upgrade from schema version 3, first used in Privacy Browser 2.5, to schema version 4, first used in Privacy Browser 2.6.
143         if (oldVersion < 4) {
144             // Add the night mode column.
145             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN nightmode INTEGER")
146         }
147
148         // Upgrade from schema version 4, first used in Privacy Browser 2.6, to schema version 5, first used in Privacy Browser 2.9.
149         if (oldVersion < 5) {
150             // Add the block lists columns.
151             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $ENABLE_EASYLIST BOOLEAN")
152             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $ENABLE_EASYPRIVACY BOOLEAN")
153             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $ENABLE_FANBOYS_ANNOYANCE_LIST BOOLEAN")
154             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST BOOLEAN")
155
156             // Get the default filter list settings.
157             val easyListEnabled = sharedPreferences.getBoolean(appContext.getString(R.string.easylist_key), true)
158             val easyPrivacyEnabled = sharedPreferences.getBoolean(appContext.getString(R.string.easyprivacy_key), true)
159             val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(appContext.getString(R.string.fanboys_annoyance_list_key), true)
160             val fanboySocialBlockingListEnabled = sharedPreferences.getBoolean(appContext.getString(R.string.fanboys_social_blocking_list_key), true)
161
162             // Set EasyList for existing rows according to the current system-wide default.
163             // This can switch to using the variables directly once the API >= 30.  <https://www.sqlite.org/datatype3.html#boolean_datatype>
164             // <https://developer.android.com/reference/android/database/sqlite/package-summary>
165             if (easyListEnabled) {
166                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_EASYLIST = 1")
167             } else {
168                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_EASYLIST = 0")
169             }
170
171             // Set EasyPrivacy for existing rows according to the current system-wide default.
172             if (easyPrivacyEnabled) {
173                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_EASYPRIVACY = 1")
174             } else {
175                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_EASYPRIVACY = 0")
176             }
177
178             // Set Fanboy's Annoyance List for existing rows according to the current system-wide default.
179             if (fanboyAnnoyanceListEnabled) {
180                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_FANBOYS_ANNOYANCE_LIST = 1")
181             } else {
182                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_FANBOYS_ANNOYANCE_LIST = 0")
183             }
184
185             // Set Fanboy's Social Blocking List for existing rows according to the current system-wide default.
186             if (fanboySocialBlockingListEnabled) {
187                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST = 1")
188             } else {
189                 domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST = 0")
190             }
191         }
192
193         // Upgrade from schema version 5, first used in Privacy Browser 2.9, to schema version 6, first used in Privacy Browser 2.11.
194         if (oldVersion < 6) {
195             // Add the swipe to refresh column.  This defaults to `0`, which is `System default`, so a separate step isn't needed to populate the column.
196             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $SWIPE_TO_REFRESH INTEGER")
197         }
198
199         // Upgrade from schema version 6, first used in Privacy Browser 2.11, to schema version 7, first used in Privacy Browser 2.12.
200         if (oldVersion < 7) {
201             // Add the block all third-party requests column.  This defaults to `0`, which is off, so a separate step isn't needed to populate the column.
202             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $BLOCK_ALL_THIRD_PARTY_REQUESTS BOOLEAN")
203         }
204
205         // Upgrade from schema version 7, first used in Privacy Browser 2.12, to schema version 8, first used in Privacy Browser 2.12.
206         // For some reason (lack of planning or attention to detail), the 2.12 update included two schema version jumps.
207         if (oldVersion < 8) {
208             // Add the UltraPrivacy column.
209             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $ENABLE_ULTRAPRIVACY BOOLEAN")
210
211             // Enable it for all existing rows.
212             domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ENABLE_ULTRAPRIVACY = 1")
213         }
214
215         // Upgrade from schema version 8, first used in Privacy Browser 2.12, to schema version 9, first used in Privacy Browser 2.16.
216         if (oldVersion < 9) {
217             // Add the pinned IP addresses columns.  These default to `0` and `""`, so a separate step isn't needed to populate the columns.
218             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $PINNED_IP_ADDRESSES BOOLEAN")
219             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $IP_ADDRESSES TEXT")
220         }
221
222         // Upgrade from schema version 9, first used in Privacy Browser 2.16, to schema version 10, first used in Privacy Browser 3.1.
223         if (oldVersion < 10) {
224             // Add the wide viewport column.  This defaults to `0`, which is `System default`, so a separate step isn't needed to populate the column.
225             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $WIDE_VIEWPORT INTEGER")
226         }
227
228         // Upgrade from schema version 10, first used in Privacy Browser 3.1, to schema version 11, first used in Privacy Browser 3.2.
229         if (oldVersion < 11) {
230             // Add the UltraList column.
231             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $ULTRALIST BOOLEAN")
232
233             // Enable it for all existing rows.
234             domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $ULTRALIST = 1")
235         }
236
237         // Upgrade from schema version 11, first used in Privacy Browser 3.2, to schema version 12, first used in Privacy Browser 3.5.
238         if (oldVersion < 12) {
239             // Add the WebView theme column.  This defaults to `0`, which is `System default`, so a separate step isn't needed to populate the column.
240             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $WEBVIEW_THEME INTEGER")
241
242             // `night_mode` was removed.
243             // SQLite amazingly only added a command to drop a column in version 3.35.0.  <https://www.sqlite.org/changes.html>
244             // It will be a while before that is supported in Android.  <https://developer.android.com/reference/android/database/sqlite/package-summary>
245             // Although a new table could be created and all the data copied to it, I think I will just leave the old night mode column.  It will be wiped out the next time an import is run.
246         }
247
248         // Upgrade from schema version 12, first used in Privacy Browser 3.5, to schema version 13, first used in Privacy Browser 3.8.
249         if (oldVersion < 13) {
250             // Add the cookies column.
251             domainsDatabase.execSQL("ALTER TABLE $DOMAINS_TABLE ADD COLUMN $COOKIES BOOLEAN")
252
253             // Copy the data from the old column to the new one.
254             domainsDatabase.execSQL("UPDATE $DOMAINS_TABLE SET $COOKIES = enablefirstpartycookies")
255         }
256
257         // Upgrade from schema version 13, first used in Privacy Browser 3.8, to schema version 14, first used in Privacy Browser 3.11.
258         // This upgrade used to add the X-Requested-With header, but that was removed in schema version 15.
259
260         // Upgrade from schema version 14, first used in Privacy Browser 3.11, to schema version 15, first used in Privacy Browser 3.12.
261         // This upgrade removed `x_requested_with_header`.
262         // SQLite amazingly only added a command to drop a column in version 3.35.0.  <https://www.sqlite.org/changes.html>
263         // It will be a while before that is supported in Android.  <https://developer.android.com/reference/android/database/sqlite/package-summary>
264         // Although a new table could be created and all the data copied to it, I think I will just leave the X-Requested-With column.  It will be wiped out the next time an import is run.
265
266         // Upgrade from schema version 15, first used in Privacy Browser 3.12, to schema version 16, first used in Privacy Browser 3.15.
267         if (oldVersion < 16) {
268             // Get the current switch default values.
269             val javaScriptDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.javascript_key), false)
270             val cookiesDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.cookies_key), false)
271             val domStorageDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.dom_storage_key), false)
272             val formDataDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.save_form_data_key), false)
273             val easyListDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.easylist_key), true)
274             val easyPrivacyDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.easyprivacy_key), true)
275             val fanboysAnnoyanceListDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.fanboys_annoyance_list_key), true)
276             val fanboysSocialBlockingListDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.fanboys_social_blocking_list), true)
277             val ultraListDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.ultralist_key), true)
278             val ultraPrivacyDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.ultraprivacy_key), true)
279             val blockAllThirdPartyRequestsDefaultValue = sharedPreferences.getBoolean(appContext.getString(R.string.block_all_third_party_requests_key), false)
280
281             // Get a domains cursor.
282             val domainsCursor = domainsDatabase.rawQuery("SELECT * FROM $DOMAINS_TABLE", null)
283
284             // Get the domains column indexes.
285             val javaScriptColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_JAVASCRIPT)
286             val cookiesColumnIndex = domainsCursor.getColumnIndexOrThrow(COOKIES)
287             val domStorageColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_DOM_STORAGE)
288             val formDataColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_FORM_DATA)
289             val easyListColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_EASYLIST)
290             val easyPrivacyColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_EASYPRIVACY)
291             val fanboysAnnoyanceListColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_ANNOYANCE_LIST)
292             val fanboysSocialBlockingListColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)
293             val ultraListColumnIndex = domainsCursor.getColumnIndexOrThrow(ULTRALIST)
294             val ultraPrivacyColumnIndex = domainsCursor.getColumnIndexOrThrow(ENABLE_ULTRAPRIVACY)
295             val blockAllThirdPartyRequestsColumnIndex = domainsCursor.getColumnIndexOrThrow(BLOCK_ALL_THIRD_PARTY_REQUESTS)
296
297             // Convert the domain from the switch booleans to the spinner integers.
298             for (i in 0 until domainsCursor.count) {
299                 // Move to the current record.
300                 domainsCursor.moveToPosition(i)
301
302                 // Get the domain current values.
303                 val javaScriptDomainCurrentValue = domainsCursor.getInt(javaScriptColumnIndex)
304                 val cookiesDomainCurrentValue = domainsCursor.getInt(cookiesColumnIndex)
305                 val domStorageDomainCurrentValue = domainsCursor.getInt(domStorageColumnIndex)
306                 val formDataDomainCurrentValue = domainsCursor.getInt(formDataColumnIndex)
307                 val easyListDomainCurrentValue = domainsCursor.getInt(easyListColumnIndex)
308                 val easyPrivacyDomainCurrentValue = domainsCursor.getInt(easyPrivacyColumnIndex)
309                 val fanboysAnnoyanceListCurrentValue = domainsCursor.getInt(fanboysAnnoyanceListColumnIndex)
310                 val fanboysSocialBlockingListCurrentValue = domainsCursor.getInt(fanboysSocialBlockingListColumnIndex)
311                 val ultraListCurrentValue = domainsCursor.getInt(ultraListColumnIndex)
312                 val ultraPrivacyCurrentValue = domainsCursor.getInt(ultraPrivacyColumnIndex)
313                 val blockAllThirdPartyRequestsCurrentValue = domainsCursor.getInt(blockAllThirdPartyRequestsColumnIndex)
314
315                 // Instantiate a domain content values.
316                 val domainContentValues = ContentValues()
317
318                 // Populate the domain content values.
319                 domainContentValues.put(ENABLE_JAVASCRIPT, convertFromSwitchToSpinner(javaScriptDefaultValue, javaScriptDomainCurrentValue))
320                 domainContentValues.put(COOKIES, convertFromSwitchToSpinner(cookiesDefaultValue, cookiesDomainCurrentValue))
321                 domainContentValues.put(ENABLE_DOM_STORAGE, convertFromSwitchToSpinner(domStorageDefaultValue, domStorageDomainCurrentValue))
322                 domainContentValues.put(ENABLE_FORM_DATA, convertFromSwitchToSpinner(formDataDefaultValue, formDataDomainCurrentValue))
323                 domainContentValues.put(ENABLE_EASYLIST, convertFromSwitchToSpinner(easyListDefaultValue, easyListDomainCurrentValue))
324                 domainContentValues.put(ENABLE_EASYPRIVACY, convertFromSwitchToSpinner(easyPrivacyDefaultValue, easyPrivacyDomainCurrentValue))
325                 domainContentValues.put(ENABLE_FANBOYS_ANNOYANCE_LIST, convertFromSwitchToSpinner(fanboysAnnoyanceListDefaultValue, fanboysAnnoyanceListCurrentValue))
326                 domainContentValues.put(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST, convertFromSwitchToSpinner(fanboysSocialBlockingListDefaultValue, fanboysSocialBlockingListCurrentValue))
327                 domainContentValues.put(ULTRALIST, convertFromSwitchToSpinner(ultraListDefaultValue, ultraListCurrentValue))
328                 domainContentValues.put(ENABLE_ULTRAPRIVACY, convertFromSwitchToSpinner(ultraPrivacyDefaultValue, ultraPrivacyCurrentValue))
329                 domainContentValues.put(BLOCK_ALL_THIRD_PARTY_REQUESTS, convertFromSwitchToSpinner(blockAllThirdPartyRequestsDefaultValue, blockAllThirdPartyRequestsCurrentValue))
330
331                 // Get the current database ID.
332                 val currentDatabaseId = domainsCursor.getInt(domainsCursor.getColumnIndexOrThrow(ID))
333
334                 // Update the row for the specified database ID.
335                 domainsDatabase.update(DOMAINS_TABLE, domainContentValues, "$ID = $currentDatabaseId", null)
336             }
337
338             // Close the cursor.
339             domainsCursor.close()
340         }
341     }
342
343     val completeCursorOrderedByDomain: Cursor
344         get() {
345             // Get a readable database handle.
346             val domainsDatabase = this.readableDatabase
347
348             // Return everything in the domains table ordered by the domain name.  The cursor can't be closed because it is needed in the calling activity.
349             return domainsDatabase.rawQuery("SELECT * FROM $DOMAINS_TABLE ORDER BY $DOMAIN_NAME ASC", null)
350         }
351
352     val domainNameCursorOrderedByDomain: Cursor
353         get() {
354             // Get a readable database handle.
355             val domainsDatabase = this.readableDatabase
356
357             // Return the database id and the domain name in the domains table ordered by the domain name.  The cursor can't be closed because it is needed in the calling activity.
358             return domainsDatabase.rawQuery("SELECT $ID, $DOMAIN_NAME FROM $DOMAINS_TABLE ORDER BY $DOMAIN_NAME ASC", null)
359         }
360     
361     // This method is used to convert the old domain settings switches to spinners.
362     private fun convertFromSwitchToSpinner(systemDefault: Boolean, currentDatabaseInteger: Int): Int {
363         // Return the new spinner integer.
364         return if ((!systemDefault && (currentDatabaseInteger == 0)) ||
365                     (systemDefault && (currentDatabaseInteger == 1)))  // The system default is currently selected.
366             SYSTEM_DEFAULT
367         else if (currentDatabaseInteger == 0)  // The switch is currently disabled and that is not the system default.
368             DISABLED
369         else  // The switch is currently enabled and that is not the system default.
370             ENABLED
371     }
372
373     fun getDomainNameCursorOrderedByDomainExcept(databaseId: Int): Cursor {
374         // Get a readable database handle.
375         val domainsDatabase = this.readableDatabase
376
377         // Return a cursor with the database IDs and domain names except for the specified ID ordered by domain name.  The cursor can't be closed because it is needed in the calling activity.
378         return domainsDatabase.rawQuery("SELECT $ID, $DOMAIN_NAME FROM $DOMAINS_TABLE WHERE $ID IS NOT $databaseId ORDER BY $DOMAIN_NAME ASC", null)
379     }
380
381     fun getCursorForId(databaseId: Int): Cursor {
382         // Get a readable database handle.
383         val domainsDatabase = this.readableDatabase
384
385         // Return a cursor for the specified database ID.  The cursor can't be closed because it is needed in the calling activity.
386         return domainsDatabase.rawQuery("SELECT * FROM $DOMAINS_TABLE WHERE $ID = $databaseId", null)
387     }
388
389     fun getCursorForDomainName(domainName: String): Cursor {
390         // Get a readable database handle.
391         val domainsDatabase = this.readableDatabase
392
393         // SQL escape the domain name.
394         val sqlEscapedDomainName = DatabaseUtils.sqlEscapeString(domainName)
395
396         // Return a cursor for the requested domain name.  The cursor can't be closed because it is needed in the calling activity.
397         return domainsDatabase.rawQuery("SELECT * FROM $DOMAINS_TABLE WHERE $DOMAIN_NAME = $sqlEscapedDomainName", null)
398     }
399
400     fun addDomain(domainName: String): Int {
401         // Instantiate a content values.
402         val domainContentValues = ContentValues()
403
404         // Get a handle for the shared preference.
405         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(appContext)
406
407         // Get the default settings.
408         val javaScript = sharedPreferences.getBoolean(appContext.getString(R.string.javascript_key), false)
409         val cookies = sharedPreferences.getBoolean(appContext.getString(R.string.cookies_key), false)
410         val domStorage = sharedPreferences.getBoolean(appContext.getString(R.string.dom_storage_key), false)
411         val saveFormData = sharedPreferences.getBoolean(appContext.getString(R.string.save_form_data_key), false)  // Form data can be removed once the minimum API >= 26.
412         val easyList = sharedPreferences.getBoolean(appContext.getString(R.string.easylist_key), true)
413         val easyPrivacy = sharedPreferences.getBoolean(appContext.getString(R.string.easyprivacy_key), true)
414         val fanboyAnnoyanceList = sharedPreferences.getBoolean(appContext.getString(R.string.fanboys_annoyance_list_key), true)
415         val fanboySocialBlockingList = sharedPreferences.getBoolean(appContext.getString(R.string.fanboys_social_blocking_list_key), true)
416         val ultraList = sharedPreferences.getBoolean(appContext.getString(R.string.ultralist_key), true)
417         val ultraPrivacy = sharedPreferences.getBoolean(appContext.getString(R.string.ultraprivacy_key), true)
418         val blockAllThirdPartyRequests = sharedPreferences.getBoolean(appContext.getString(R.string.block_all_third_party_requests_key), false)
419
420         // Create entries for the database fields.  The ID is created automatically.  The pinned SSL certificate information is not created unless added by the user.
421         domainContentValues.put(DOMAIN_NAME, domainName)
422         domainContentValues.put(ENABLE_JAVASCRIPT, javaScript)
423         domainContentValues.put(COOKIES, cookies)
424         domainContentValues.put(ENABLE_DOM_STORAGE, domStorage)
425         domainContentValues.put(ENABLE_FORM_DATA, saveFormData) // Form data can be removed once the minimum API >= 26.
426         domainContentValues.put(ENABLE_EASYLIST, easyList)
427         domainContentValues.put(ENABLE_EASYPRIVACY, easyPrivacy)
428         domainContentValues.put(ENABLE_FANBOYS_ANNOYANCE_LIST, fanboyAnnoyanceList)
429         domainContentValues.put(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST, fanboySocialBlockingList)
430         domainContentValues.put(ULTRALIST, ultraList)
431         domainContentValues.put(ENABLE_ULTRAPRIVACY, ultraPrivacy)
432         domainContentValues.put(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests)
433         domainContentValues.put(USER_AGENT, appContext.getString(R.string.system_default_user_agent))
434         domainContentValues.put(FONT_SIZE, 0)
435         domainContentValues.put(SWIPE_TO_REFRESH, 0)
436         domainContentValues.put(WEBVIEW_THEME, 0)
437         domainContentValues.put(WIDE_VIEWPORT, 0)
438         domainContentValues.put(DISPLAY_IMAGES, 0)
439
440         // Get a writable database handle.
441         val domainsDatabase = this.writableDatabase
442
443         // Insert a new row and store the resulting database ID.
444         val newDomainDatabaseId = domainsDatabase.insert(DOMAINS_TABLE, null, domainContentValues).toInt()
445
446         // Close the database handle.
447         domainsDatabase.close()
448
449         // Return the new domain database ID.
450         return newDomainDatabaseId
451     }
452
453     fun addDomain(contentValues: ContentValues) {
454         // Get a writable database handle.
455         val domainsDatabase = this.writableDatabase
456
457         // Add the new domain.
458         domainsDatabase.insert(DOMAINS_TABLE, null, contentValues)
459
460         // Close the database handle.
461         domainsDatabase.close()
462     }
463
464     fun updateDomain(databaseId: Int, domainName: String, javaScript: Int, cookies: Int, domStorage: Int, formData: Int, easyList: Int, easyPrivacy: Int, fanboysAnnoyance: Int, fanboysSocialBlocking: Int,
465                      ultraList: Int, ultraPrivacy: Int, blockAllThirdPartyRequests: Int, userAgent: String, fontSize: Int, swipeToRefresh: Int, webViewTheme: Int, wideViewport: Int, displayImages: Int,
466                      pinnedSslCertificate: Boolean, pinnedIpAddresses: Boolean) {
467
468         // Instantiate a content values.
469         val domainContentValues = ContentValues()
470
471         // Add entries for each field in the database.
472         domainContentValues.put(DOMAIN_NAME, domainName)
473         domainContentValues.put(ENABLE_JAVASCRIPT, javaScript)
474         domainContentValues.put(COOKIES, cookies)
475         domainContentValues.put(ENABLE_DOM_STORAGE, domStorage)
476         domainContentValues.put(ENABLE_FORM_DATA, formData) // Form data can be removed once the minimum API >= 26.
477         domainContentValues.put(ENABLE_EASYLIST, easyList)
478         domainContentValues.put(ENABLE_EASYPRIVACY, easyPrivacy)
479         domainContentValues.put(ENABLE_FANBOYS_ANNOYANCE_LIST, fanboysAnnoyance)
480         domainContentValues.put(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST, fanboysSocialBlocking)
481         domainContentValues.put(ULTRALIST, ultraList)
482         domainContentValues.put(ENABLE_ULTRAPRIVACY, ultraPrivacy)
483         domainContentValues.put(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests)
484         domainContentValues.put(USER_AGENT, userAgent)
485         domainContentValues.put(FONT_SIZE, fontSize)
486         domainContentValues.put(SWIPE_TO_REFRESH, swipeToRefresh)
487         domainContentValues.put(WEBVIEW_THEME, webViewTheme)
488         domainContentValues.put(WIDE_VIEWPORT, wideViewport)
489         domainContentValues.put(DISPLAY_IMAGES, displayImages)
490         domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate)
491         domainContentValues.put(PINNED_IP_ADDRESSES, pinnedIpAddresses)
492
493         // Get a writable database handle.
494         val domainsDatabase = this.writableDatabase
495
496         // Update the row for the specified database ID.
497         domainsDatabase.update(DOMAINS_TABLE, domainContentValues, "$ID = $databaseId", null)
498
499         // Close the database handle.
500         domainsDatabase.close()
501     }
502
503     fun updatePinnedSslCertificate(databaseId: Int, sslIssuedToCommonName: String, sslIssuedToOrganization: String, sslIssuedToOrganizationalUnit: String, sslIssuedByCommonName: String,
504                                    sslIssuedByOrganization: String, sslIssuedByOrganizationalUnit: String, sslStartDate: Long, sslEndDate: Long) {
505         // Instantiate a content values.
506         val pinnedSslCertificateContentValues = ContentValues()
507
508         // Add entries for each field in the certificate.
509         pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName)
510         pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization)
511         pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit)
512         pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName)
513         pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization)
514         pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit)
515         pinnedSslCertificateContentValues.put(SSL_START_DATE, sslStartDate)
516         pinnedSslCertificateContentValues.put(SSL_END_DATE, sslEndDate)
517
518         // Get a writable database handle.
519         val domainsDatabase = this.writableDatabase
520
521         // Update the row for the specified database ID.
522         domainsDatabase.update(DOMAINS_TABLE, pinnedSslCertificateContentValues, "$ID = $databaseId", null)
523
524         // Close the database handle.
525         domainsDatabase.close()
526     }
527
528     fun updatePinnedIpAddresses(databaseId: Int, ipAddresses: String) {
529         // Instantiate a content values.
530         val pinnedIpAddressesContentValues = ContentValues()
531
532         // Add the IP addresses to the content values.
533         pinnedIpAddressesContentValues.put(IP_ADDRESSES, ipAddresses)
534
535         // Get a writable database handle.
536         val domainsDatabase = this.writableDatabase
537
538         // Update the row for the database ID.
539         domainsDatabase.update(DOMAINS_TABLE, pinnedIpAddressesContentValues, "$ID = $databaseId", null)
540
541         // Close the database handle.
542         domainsDatabase.close()
543     }
544
545     fun deleteDomain(databaseId: Int) {
546         // Get a writable database handle.
547         val domainsDatabase = this.writableDatabase
548
549         // Delete the row for the specified database ID.
550         domainsDatabase.delete(DOMAINS_TABLE, "$ID = $databaseId", null)
551
552         // Close the database handle.
553         domainsDatabase.close()
554     }
555 }