+ // Create a temporary import file string.
+ String temporaryImportFileString = context.getCacheDir() + "/" + "temporary_import_file";
+
+ // Get a handle for a temporary import file.
+ File temporaryImportFile = new File(temporaryImportFileString);
+
+ // Delete the temporary import file if it already exists.
+ if (temporaryImportFile.exists()) {
+ //noinspection ResultOfMethodCallIgnored
+ temporaryImportFile.delete();
+ }
+
+ // Create input and output streams.
+ InputStream importFileInputStream = new FileInputStream(importFile);
+ OutputStream temporaryImportFileOutputStream = new FileOutputStream(temporaryImportFile);
+
+ // Create a byte array.
+ byte[] transferByteArray = new byte[1024];
+
+ // Create an integer to track the number of bytes read.
+ int bytesRead;
+
+ // Copy the import file to the temporary import file. Once the minimum API >= 26 `Files.copy` can be used instead.
+ while ((bytesRead = importFileInputStream.read(transferByteArray)) > 0) {
+ temporaryImportFileOutputStream.write(transferByteArray, 0, bytesRead);
+ }
+
+ // Close the file streams.
+ importFileInputStream.close();
+ temporaryImportFileOutputStream.close();
+
+
+ // Get a handle for the shared preference.
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ // Open the import database. Once the minimum API >= 27 the file can be opened directly without using the string.
+ SQLiteDatabase importDatabase = SQLiteDatabase.openDatabase(temporaryImportFileString, null, SQLiteDatabase.OPEN_READWRITE);
+
+ // Get the database version.
+ int importDatabaseVersion = importDatabase.getVersion();
+
+ // Upgrade the database if needed.
+ if (importDatabaseVersion < SCHEMA_VERSION) {
+ switch (importDatabaseVersion){
+ // Upgrade from schema version 1, Privacy Browser 2.13.
+ case 1:
+ // Previously this upgrade added `download_with_external_app` to the Preferences table. But that is now removed in schema version 10.
+
+ // Upgrade from schema version 2, Privacy Browser 2.14.
+ case 2:
+ // Once the SQLite version is >= 3.25.0 `ALTER TABLE RENAME COLUMN` can be used. https://www.sqlite.org/lang_altertable.html https://www.sqlite.org/changes.html
+ // https://developer.android.com/reference/android/database/sqlite/package-summary
+ // In the meantime, a new column must be created with the new name. There is no need to delete the old column on the temporary import database.
+
+ // Get a cursor with the current `default_font_size` value.
+ Cursor importDatabasePreferenceCursor = importDatabase.rawQuery("SELECT default_font_size FROM " + PREFERENCES_TABLE, null);
+
+ // Move to the beginning fo the cursor.
+ importDatabasePreferenceCursor.moveToFirst();
+
+ // Get the current value in `default_font_size`.
+ String fontSize = importDatabasePreferenceCursor.getString(importDatabasePreferenceCursor.getColumnIndex("default_font_size"));
+
+ // SQL escape the font size.
+ fontSize = DatabaseUtils.sqlEscapeString(fontSize);
+
+ // Close the cursor.
+ importDatabasePreferenceCursor.close();
+
+ // Create the new font size column.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + FONT_SIZE + " TEXT");
+
+ // Populate the preferences table with the current font size value.
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + FONT_SIZE + " = '" + fontSize + "'");
+
+ // Upgrade from schema version 3, Privacy Browser 2.15.
+ case 3:
+ // Add the Pinned IP Addresses columns to the domains table.
+ importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.PINNED_IP_ADDRESSES + " BOOLEAN");
+ importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.IP_ADDRESSES + " TEXT");
+
+ // Upgrade from schema version 4, Privacy Browser 2.16.
+ case 4:
+ // Add the hide and scroll app bar columns to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + HIDE_APP_BAR + " BOOLEAN");
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + SCROLL_APP_BAR + " BOOLEAN");
+
+ // Get the current hide and scroll app bar settings.
+ boolean hideAppBar = sharedPreferences.getBoolean(HIDE_APP_BAR, true);
+ boolean scrollAppBar = sharedPreferences.getBoolean(SCROLL_APP_BAR, true);
+
+ // Populate the preferences table with the current app bar values.
+ if (hideAppBar) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + HIDE_APP_BAR + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + HIDE_APP_BAR + " = " + 0);
+ }
+
+ if (scrollAppBar) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + SCROLL_APP_BAR + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + SCROLL_APP_BAR + " = " + 0);
+ }
+
+ // Upgrade from schema version 5, Privacy Browser 2.17.
+ case 5:
+ // Add the open intents in new tab column to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + OPEN_INTENTS_IN_NEW_TAB + " BOOLEAN");
+
+ // Get the current open intents in new tab preference.
+ boolean openIntentsInNewTab = sharedPreferences.getBoolean(OPEN_INTENTS_IN_NEW_TAB, true);
+
+ // Populate the preferences table with the current open intents value.
+ if (openIntentsInNewTab) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + OPEN_INTENTS_IN_NEW_TAB + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + OPEN_INTENTS_IN_NEW_TAB + " = " + 0);
+ }
+
+ // Upgrade from schema version 6, Privacy Browser 3.0.
+ case 6:
+ // Add the wide viewport column to the domains table.
+ importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.WIDE_VIEWPORT + " INTEGER");
+
+ // Add the Google Analytics, Facebook Click IDs, Twitter AMP redirects, and wide viewport columns to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + GOOGLE_ANALYTICS + " BOOLEAN");
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + FACEBOOK_CLICK_IDS + " BOOLEAN");
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + TWITTER_AMP_REDIRECTS + " BOOLEAN");
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + WIDE_VIEWPORT + " BOOLEAN");
+
+ // Get the current preference values.
+ boolean googleAnalytics = sharedPreferences.getBoolean(GOOGLE_ANALYTICS, true);
+ boolean facebookClickIds = sharedPreferences.getBoolean(FACEBOOK_CLICK_IDS, true);
+ boolean twitterAmpRedirects = sharedPreferences.getBoolean(TWITTER_AMP_REDIRECTS, true);
+ boolean wideViewport = sharedPreferences.getBoolean(WIDE_VIEWPORT, true);
+
+ // Populate the preferences with the current Google Analytics value.
+ if (googleAnalytics) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + GOOGLE_ANALYTICS + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + GOOGLE_ANALYTICS + " = " + 0);
+ }
+
+ // Populate the preferences with the current Facebook Click IDs value.
+ if (facebookClickIds) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + FACEBOOK_CLICK_IDS + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + FACEBOOK_CLICK_IDS + " = " + 0);
+ }
+
+ // Populate the preferences table with the current Twitter AMP redirects value.
+ if (twitterAmpRedirects) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + TWITTER_AMP_REDIRECTS + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + TWITTER_AMP_REDIRECTS + " = " + 0);
+ }
+
+ // Populate the preferences table with the current wide viewport value.
+ if (wideViewport) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + WIDE_VIEWPORT + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + WIDE_VIEWPORT + " = " + 0);
+ }
+
+ // Upgrade from schema version 7, Privacy Browser 3.1.
+ case 7:
+ // Add the UltraList column to the domains table.
+ importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.ULTRALIST + " BOOLEAN");
+
+ // Add the UltraList column to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + ULTRALIST + " BOOLEAN");
+
+ // Get the current preference values.
+ boolean ultraList = sharedPreferences.getBoolean(ULTRALIST, true);
+
+ // Populate the preferences tables with the current UltraList value.
+ if (ultraList) {
+ importDatabase.execSQL("UPDATE " + DomainsDatabaseHelper.DOMAINS_TABLE + " SET " + DomainsDatabaseHelper.ULTRALIST + " = " + 1);
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + ULTRALIST + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + DomainsDatabaseHelper.DOMAINS_TABLE + " SET " + DomainsDatabaseHelper.ULTRALIST + " = " + 0);
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + ULTRALIST + " = " + 0);
+ }
+
+ // Upgrade from schema version 8, Privacy Browser 3.2.
+ case 8:
+ // Add the new proxy columns to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + PROXY + " TEXT");
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + PROXY_CUSTOM_URL + " TEXT");
+
+ // Get the current proxy values.
+ String proxy = sharedPreferences.getString(PROXY, context.getString(R.string.proxy_default_value));
+ String proxyCustomUrl = sharedPreferences.getString(PROXY_CUSTOM_URL, context.getString(R.string.proxy_custom_url_default_value));
+
+ // SQL escape the proxy custom URL string.
+ proxyCustomUrl = DatabaseUtils.sqlEscapeString(proxyCustomUrl);
+
+ // Populate the preferences table with the current proxy values. The proxy custom URL does not need to be surrounded by `'` because it was SLQ escaped above.
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + PROXY + " = '" + proxy + "'");
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + PROXY_CUSTOM_URL + " = " + proxyCustomUrl);
+
+ // Upgrade from schema version 9, Privacy Browser 3.3.
+ case 9:
+ // Add the download location columns to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + DOWNLOAD_LOCATION + " TEXT");
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + DOWNLOAD_CUSTOM_LOCATION + " TEXT");
+
+ // Get the current download location values.
+ String downloadLocation = sharedPreferences.getString(DOWNLOAD_LOCATION, context.getString(R.string.download_location_default_value));
+ String downloadCustomLocation = sharedPreferences.getString(DOWNLOAD_CUSTOM_LOCATION, context.getString(R.string.download_custom_location_default_value));
+
+ // Populate the preferences table with the current download location values.
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + DOWNLOAD_LOCATION + " = '" + downloadLocation + "'");
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + DOWNLOAD_CUSTOM_LOCATION + " = '" + downloadCustomLocation + "'");
+
+ // Upgrade from schema version 10, Privacy Browser 3.4.
+ case 10:
+ // Add the app theme column to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + APP_THEME + " TEXT");
+
+ // Get a cursor for the dark theme preference.
+ Cursor darkThemePreferencesCursor = importDatabase.rawQuery("SELECT dark_theme FROM " + PREFERENCES_TABLE, null);
+
+ // Move to the first preference.
+ darkThemePreferencesCursor.moveToFirst();
+
+ // Get the old dark theme value, which is in column 0.
+ int darkTheme = darkThemePreferencesCursor.getInt(0);
+
+ // Close the dark theme preference cursor.
+ darkThemePreferencesCursor.close();
+
+ // Populate the app theme according to the old dark theme preference.
+ if (darkTheme == 0) { // A light theme was selected.
+ // Set the app theme to be the system default.
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + APP_THEME + " = 'System default'");
+ } else { // A dark theme was selected.
+ // Set the app theme to be dark.
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + APP_THEME + " = 'Dark'");
+ }
+
+ // Add the WebView theme to the domains table. This defaults to 0, which is `System default`, so a separate step isn't needed to populate the database.
+ importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.WEBVIEW_THEME + " INTEGER");
+
+ // Add the WebView theme to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + WEBVIEW_THEME + " TEXT");
+
+ // Get the WebView theme default value string.
+ String webViewThemeDefaultValue = context.getString(R.string.webview_theme_default_value);
+
+ // Set the WebView theme in the preferences table to be the default.
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + WEBVIEW_THEME + " = " + "'" + webViewThemeDefaultValue + "'");
+
+ // Upgrade from schema version 11, Privacy Browser 3.5.
+ case 11:
+ // Add the clear logcat column to the preferences table.
+ importDatabase.execSQL("ALTER TABLE " + PREFERENCES_TABLE + " ADD COLUMN " + CLEAR_LOGCAT + " BOOLEAN");
+
+ // Get the current clear logcat value.
+ boolean clearLogcat = sharedPreferences.getBoolean(CLEAR_LOGCAT, true);
+
+ // Populate the preference table with the current clear logcat value.
+ if (clearLogcat) {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + CLEAR_LOGCAT + " = " + 1);
+ } else {
+ importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + CLEAR_LOGCAT + " = " + 0);
+ }
+ }
+ }
+
+
+ // Get a cursor for the bookmarks table.
+ Cursor importBookmarksCursor = importDatabase.rawQuery("SELECT * FROM " + BookmarksDatabaseHelper.BOOKMARKS_TABLE, null);
+
+ // Delete the current bookmarks database.
+ context.deleteDatabase(BookmarksDatabaseHelper.BOOKMARKS_DATABASE);
+
+ // Create a new bookmarks database. The `0` specifies the database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
+ BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(context, null, null, 0);
+
+ // Move to the first bookmark.
+ importBookmarksCursor.moveToFirst();
+
+ // Copy the data from the import bookmarks cursor into the bookmarks database.
+ for (int i = 0; i < importBookmarksCursor.getCount(); i++) {
+ // Extract the record from the cursor and store the data in a ContentValues.
+ ContentValues bookmarksContentValues = new ContentValues();
+ bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_NAME, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)));
+ bookmarksContentValues.put(BookmarksDatabaseHelper.BOOKMARK_URL, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)));
+ bookmarksContentValues.put(BookmarksDatabaseHelper.PARENT_FOLDER, importBookmarksCursor.getString(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER)));
+ bookmarksContentValues.put(BookmarksDatabaseHelper.DISPLAY_ORDER, importBookmarksCursor.getInt(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)));
+ bookmarksContentValues.put(BookmarksDatabaseHelper.IS_FOLDER, importBookmarksCursor.getInt(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.IS_FOLDER)));
+ bookmarksContentValues.put(BookmarksDatabaseHelper.FAVORITE_ICON, importBookmarksCursor.getBlob(importBookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON)));
+
+ // Insert the record into the export database.
+ bookmarksDatabaseHelper.createBookmark(bookmarksContentValues);
+
+ // Advance to the next record.
+ importBookmarksCursor.moveToNext();
+ }
+
+ // Close the bookmarks cursor.
+ importBookmarksCursor.close();
+
+ // Close the bookmarks database.
+ bookmarksDatabaseHelper.close();