From: Soren Stoutner Date: Thu, 30 Apr 2026 17:50:50 +0000 (-0700) Subject: Bump the minimum API from 26 to 29. X-Git-Url: https://gitweb.stoutner.com/?a=commitdiff_plain;h=1ab0c1f749f002e3359dd7345b15d9fc86c1c9ee;p=PrivacyBrowserAndroid.git Bump the minimum API from 26 to 29. --- diff --git a/app/build.gradle b/app/build.gradle index adb26e94..6c2d0240 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,7 +28,7 @@ android { compileSdk = 36 defaultConfig { - minSdk 26 + minSdk 29 targetSdk 36 versionCode 81 versionName "3.20.1" diff --git a/app/src/main/assets/de/about_changelog.html b/app/src/main/assets/de/about_changelog.html index df17a1c8..f3e382ba 100644 --- a/app/src/main/assets/de/about_changelog.html +++ b/app/src/main/assets/de/about_changelog.html @@ -34,7 +34,7 @@

3.20.1 (Code-Version 81)

-

30. März 2026 - Mindest-API 26, Ziel-API 36

+

30. März 2026 - Mindest-API 26, Ziel-API 36

diff --git a/app/src/main/assets/en/about_changelog.html b/app/src/main/assets/en/about_changelog.html index 861a2f3c..45e50ef7 100644 --- a/app/src/main/assets/en/about_changelog.html +++ b/app/src/main/assets/en/about_changelog.html @@ -30,7 +30,7 @@

3.20.1 (version code 81)

-

30 March 2026 - minimum API 26, target API 36

+

30 March 2026 - minimum API 26, target API 36

diff --git a/app/src/main/assets/es/about_changelog.html b/app/src/main/assets/es/about_changelog.html index 2c7063c6..2d969ba3 100644 --- a/app/src/main/assets/es/about_changelog.html +++ b/app/src/main/assets/es/about_changelog.html @@ -32,7 +32,7 @@

3.20.1 (código de versión 81)

-

30 de marzo de 2026 - API mínimo 26, API objetivo 36

+

30 de marzo de 2026 - API mínimo 26, API objetivo 36

diff --git a/app/src/main/assets/fr/about_changelog.html b/app/src/main/assets/fr/about_changelog.html index a53d6612..4d29f612 100644 --- a/app/src/main/assets/fr/about_changelog.html +++ b/app/src/main/assets/fr/about_changelog.html @@ -32,7 +32,7 @@

3.20.1 (version du code 81)

-

30 Mars 2026 - API minimale : 26, API optimale : 36

+

30 Mars 2026 - API minimale : 26, API optimale : 36

diff --git a/app/src/main/assets/it/about_changelog.html b/app/src/main/assets/it/about_changelog.html index 0e21eaeb..a8e48649 100644 --- a/app/src/main/assets/it/about_changelog.html +++ b/app/src/main/assets/it/about_changelog.html @@ -32,7 +32,7 @@

3.20.1 (versione codice 81)

-

30 Marzo 2026 - minima API 26, target API 36

+

30 Marzo 2026 - minima API 26, target API 36

diff --git a/app/src/main/assets/pt-rBR/about_changelog.html b/app/src/main/assets/pt-rBR/about_changelog.html index dc61105b..d9ef3853 100644 --- a/app/src/main/assets/pt-rBR/about_changelog.html +++ b/app/src/main/assets/pt-rBR/about_changelog.html @@ -32,7 +32,7 @@

3.20.1 (código de versão 81)

-

30 de março de 2026 - minimum API 26, target API 36

+

30 de março de 2026 - minimum API 26, target API 36

diff --git a/app/src/main/assets/ru/about_changelog.html b/app/src/main/assets/ru/about_changelog.html index e052bb06..45abc395 100644 --- a/app/src/main/assets/ru/about_changelog.html +++ b/app/src/main/assets/ru/about_changelog.html @@ -30,7 +30,7 @@

3.20.1 (код версии 81)

-

30 марта 2026 года - минимальный API 26, целевой API 36

+

30 марта 2026 года - минимальный API 26, целевой API 36

diff --git a/app/src/main/assets/tr/about_changelog.html b/app/src/main/assets/tr/about_changelog.html index 32d0defd..d5dc62dc 100644 --- a/app/src/main/assets/tr/about_changelog.html +++ b/app/src/main/assets/tr/about_changelog.html @@ -30,7 +30,7 @@

3.20.1 (version code 81)

-

30 Mart 2026 - minimum API 26, target API 36

+

30 Mart 2026 - minimum API 26, target API 36

diff --git a/app/src/main/assets/zh-rCN/about_changelog.html b/app/src/main/assets/zh-rCN/about_changelog.html index f7c01988..05094f46 100644 --- a/app/src/main/assets/zh-rCN/about_changelog.html +++ b/app/src/main/assets/zh-rCN/about_changelog.html @@ -32,7 +32,7 @@

3.20.1 (version code 81)

-

30 March 2026 - 最低支持API 26, 最高支持API 36

+

30 March 2026 - 最低支持API 26, 最高支持API 36

diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.kt index 62b46a82..41953397 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.kt @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * SPDX-FileCopyrightText: 2018-2025 Soren Stoutner + * SPDX-FileCopyrightText: 2018-2026 Soren Stoutner * * This file is part of Privacy Browser Android . * @@ -43,6 +43,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.cardview.widget.CardView import androidx.core.content.FileProvider +import androidx.core.net.toUri import androidx.preference.PreferenceManager import com.google.android.material.snackbar.Snackbar @@ -240,7 +241,7 @@ class ImportExportActivity : AppCompatActivity() { openKeychainInstalled = try { // If the safe call (`?.`) is null, the Elvis operator (`?"`) returns the following value instead, which is `false`. packageManager.getPackageInfo("org.sufficientlysecure.keychain", 0).versionName?.isNotEmpty() ?: false - } catch (exception: PackageManager.NameNotFoundException) { + } catch (_: PackageManager.NameNotFoundException) { // The package is not installed false } @@ -266,7 +267,7 @@ class ImportExportActivity : AppCompatActivity() { // Create an array adapter for the spinner. val encryptionArrayAdapter = ArrayAdapter.createFromResource(this, R.array.encryption_type, R.layout.spinner_item) - // Set the drop down view resource on the spinner. + // Set the drop-down view resource on the spinner. encryptionArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_items) // Set the array adapter for the spinner. @@ -620,8 +621,7 @@ class ImportExportActivity : AppCompatActivity() { NO_ENCRYPTION -> { try { // Get an input stream for the file name. - // A file may be opened directly once the minimum API >= 29. - val inputStream = contentResolver.openInputStream(Uri.parse(fileNameString))!! + val inputStream = contentResolver.openInputStream(fileNameString.toUri())!! // Import the unencrypted file. importStatus = importExportDatabaseHelper.importUnencrypted(inputStream, this) @@ -644,7 +644,7 @@ class ImportExportActivity : AppCompatActivity() { val encryptionPasswordString = encryptionPasswordEditText.text.toString() // Get an input stream for the file name. - val inputStream = contentResolver.openInputStream(Uri.parse(fileNameString))!! + val inputStream = contentResolver.openInputStream(fileNameString.toUri())!! // Initialize a salt byte array. Salt protects against rainbow table attacks. val saltByteArray = ByteArray(32) @@ -670,19 +670,19 @@ class ImportExportActivity : AppCompatActivity() { // Populate the second part of the encryption password with salt byte array with the salt. System.arraycopy(saltByteArray, 0, encryptionPasswordWithSaltByteArray, encryptionPasswordByteArray.size, saltByteArray.size) - // Get a SHA-512 message digest. + // Get an SHA-512 message digest. val messageDigest = MessageDigest.getInstance("SHA-512") // Hash the salted encryption password. Otherwise, any characters after the 32nd character in the password are ignored. val hashedEncryptionPasswordWithSaltByteArray = messageDigest.digest(encryptionPasswordWithSaltByteArray) // Truncate the encryption password byte array to 256 bits (32 bytes). - val truncatedHashedEncryptionPasswordWithSaltByteArray = Arrays.copyOf(hashedEncryptionPasswordWithSaltByteArray, 32) + val truncatedHashedEncryptionPasswordWithSaltByteArray = hashedEncryptionPasswordWithSaltByteArray.copyOf(32) // Create an AES secret key from the encryption password byte array. val secretKey = SecretKeySpec(truncatedHashedEncryptionPasswordWithSaltByteArray, "AES") - // Get a Advanced Encryption Standard, Galois/Counter Mode, No Padding cipher instance. Galois/Counter mode protects against modification of the ciphertext. It doesn't use padding. + // Get an Advanced Encryption Standard, Galois/Counter Mode, No Padding cipher instance. Galois/Counter mode protects against modification of the ciphertext. It doesn't use padding. val cipher = Cipher.getInstance("AES/GCM/NoPadding") // Set the GCM tag length to be 128 bits (the maximum) and apply the initialization vector. @@ -701,7 +701,7 @@ class ImportExportActivity : AppCompatActivity() { // Create a private temporary unencrypted import file. val temporaryUnencryptedImportFile = File.createTempFile("temporary_unencrypted_import_file", null, applicationContext.cacheDir) - // Create an temporary unencrypted import file output stream. + // Create a temporary unencrypted import file output stream. val temporaryUnencryptedImportFileOutputStream = FileOutputStream(temporaryUnencryptedImportFile) // Read up to 128 bits (16 bytes) of data from the cipher input stream. `-1` will be returned when the end of the file is reached. @@ -763,7 +763,7 @@ class ImportExportActivity : AppCompatActivity() { val temporaryPgpEncryptedImportFileOutputStream = FileOutputStream(temporaryPgpEncryptedImportFile) // Get an input stream for the file name. - val inputStream = contentResolver.openInputStream(Uri.parse(fileNameString))!! + val inputStream = contentResolver.openInputStream(fileNameString.toUri())!! // Create a transfer byte array. val transferByteArray = ByteArray(1024) @@ -818,8 +818,7 @@ class ImportExportActivity : AppCompatActivity() { try { // Get the export file output stream, truncating any existing content. - // A file may be opened directly once the minimum API >= 29. - val exportFileOutputStream = contentResolver.openOutputStream(Uri.parse(noEncryptionFileNameString), "wt")!! + val exportFileOutputStream = contentResolver.openOutputStream(noEncryptionFileNameString.toUri(), "wt")!! // Export the unencrypted file. val noEncryptionExportStatus = importExportDatabaseHelper.exportUnencrypted(exportFileOutputStream, this) @@ -879,14 +878,14 @@ class ImportExportActivity : AppCompatActivity() { // Populate the second part of the encryption password with salt byte array with the salt. System.arraycopy(saltByteArray, 0, encryptionPasswordWithSaltByteArray, encryptionPasswordByteArray.size, saltByteArray.size) - // Get a SHA-512 message digest. + // Get an SHA-512 message digest. val messageDigest = MessageDigest.getInstance("SHA-512") // Hash the salted encryption password. Otherwise, any characters after the 32nd character in the password are ignored. val hashedEncryptionPasswordWithSaltByteArray = messageDigest.digest(encryptionPasswordWithSaltByteArray) // Truncate the encryption password byte array to 256 bits (32 bytes). - val truncatedHashedEncryptionPasswordWithSaltByteArray = Arrays.copyOf(hashedEncryptionPasswordWithSaltByteArray, 32) + val truncatedHashedEncryptionPasswordWithSaltByteArray = hashedEncryptionPasswordWithSaltByteArray.copyOf(32) // Create an AES secret key from the encryption password byte array. val secretKey = SecretKeySpec(truncatedHashedEncryptionPasswordWithSaltByteArray, "AES") @@ -897,7 +896,7 @@ class ImportExportActivity : AppCompatActivity() { // Populate the initialization vector with random data. secureRandom.nextBytes(initializationVector) - // Get a Advanced Encryption Standard, Galois/Counter Mode, No Padding cipher instance. Galois/Counter mode protects against modification of the ciphertext. It doesn't use padding. + // Get an Advanced Encryption Standard, Galois/Counter Mode, No Padding cipher instance. Galois/Counter mode protects against modification of the ciphertext. It doesn't use padding. val cipher = Cipher.getInstance("AES/GCM/NoPadding") // Set the GCM tag length to be 128 bits (the maximum) and apply the initialization vector. @@ -910,7 +909,7 @@ class ImportExportActivity : AppCompatActivity() { val passwordEncryptionFileNameString = settingsFileNameEditText.text.toString() // Get the export file output stream, truncating any existing content. - val exportFileOutputStream = contentResolver.openOutputStream(Uri.parse(passwordEncryptionFileNameString), "wt")!! + val exportFileOutputStream = contentResolver.openOutputStream(passwordEncryptionFileNameString.toUri(), "wt")!! // Add the salt and the initialization vector to the export file output stream. exportFileOutputStream.write(saltByteArray) diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt index d4306343..b33db873 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * SPDX-FileCopyrightText: 2019-2025 Soren Stoutner + * SPDX-FileCopyrightText: 2019-2026 Soren Stoutner * * This file is part of Privacy Browser Android . * @@ -312,7 +312,7 @@ class LogcatActivity : AppCompatActivity() { // Reload the logcat. populateLogcat() - } catch (exception: Exception) { + } catch (_: Exception) { // Do nothing. } @@ -387,19 +387,19 @@ class LogcatActivity : AppCompatActivity() { logcatLineString = logcatLineString!!.trim() // Apply syntax highlighting to the logcat. - if (logcatLineString!!.contains("crash") || logcatLineString!!.contains("Exception") ) { // Colorize crashes. + if (logcatLineString.contains("crash") || logcatLineString.contains("Exception") ) { // Colorize crashes. logcatHtmlStringBuilder.append("") logcatHtmlStringBuilder.append(logcatLineString) logcatHtmlStringBuilder.append("") - } else if (logcatLineString!!.startsWith("at") || logcatLineString!!.startsWith("Process:") || logcatLineString!!.contains("FATAL")) { // Colorize lines relating to crashes. + } else if (logcatLineString.startsWith("at") || logcatLineString.startsWith("Process:") || logcatLineString.contains("FATAL")) { // Colorize lines relating to crashes. logcatHtmlStringBuilder.append("") logcatHtmlStringBuilder.append(logcatLineString) logcatHtmlStringBuilder.append("") - } else if (logcatLineString!!.startsWith("-")) { // Colorize the headers. + } else if (logcatLineString.startsWith("-")) { // Colorize the headers. logcatHtmlStringBuilder.append("") logcatHtmlStringBuilder.append(logcatLineString) logcatHtmlStringBuilder.append("") - } else if (logcatLineString!!.startsWith("[ ")) { // Colorize the time stamps. + } else if (logcatLineString.startsWith("[ ")) { // Colorize the time stamps. logcatHtmlStringBuilder.append("") logcatHtmlStringBuilder.append(logcatLineString) logcatHtmlStringBuilder.append("") @@ -423,7 +423,7 @@ class LogcatActivity : AppCompatActivity() { // Close the buffered reader. logcatBufferedReader.close() - } catch (exception: IOException) { + } catch (_: IOException) { // Do nothing. } diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt index 86d778e4..003010b4 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt @@ -518,11 +518,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook displayUnderCutouts = sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false) // Set the display under cutouts mode. This must be done here as it doesn't appear to work correctly if handled after the app is fully initialized. - if ((Build.VERSION.SDK_INT < 35) && displayUnderCutouts) { - if (Build.VERSION.SDK_INT >= 30) - window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS - else if (Build.VERSION.SDK_INT >= 28) + if ((Build.VERSION.SDK_INT <= 34) && displayUnderCutouts) { + if (Build.VERSION.SDK_INT <= 29) window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES + else + window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS } // Get the entry values string arrays. @@ -532,20 +532,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK // Set the app theme according to the preference. A switch statement cannot be used because the theme entry values string array is not a compile time constant. - if (appTheme == appThemeEntryValuesStringArray[1]) { // The light theme is selected. - // Apply the light theme. - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) - } else if (appTheme == appThemeEntryValuesStringArray[2]) { // The dark theme is selected. - // Apply the dark theme. - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) - } else { // The system default theme is selected. - if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported. - // Follow the system default theme. - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) - } else { // The system default theme is not supported. - // Follow the battery saver mode. - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY) - } + when (appTheme) { + appThemeEntryValuesStringArray[1] -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) // The light theme is selected. + appThemeEntryValuesStringArray[2] -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) // The dark theme is selected. + else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) // The system default theme is selected. } // Do not continue if the app theme is different than the OS theme. The app always initially starts in the OS theme. @@ -6191,11 +6181,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook // Set the download destination. downloadRequest.setDestinationInExternalPublicDir(downloadDirectory, fileNameString) - // Allow media scanner to index the download if it is a media file. This is automatic for API >= 29. - @Suppress("DEPRECATION") - if (Build.VERSION.SDK_INT <= 28) - downloadRequest.allowScanningByMediaScanner() - // Add the URL as the description for the download. downloadRequest.setDescription(saveUrlString) diff --git a/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt b/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt index 030acd2b..b1590dfc 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/backgroundtasks/GetHeadersBackgroundTask.kt @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * SPDX-FileCopyrightText: 2017-2024 Soren Stoutner + * SPDX-FileCopyrightText: 2017-2024, 2026 Soren Stoutner * * This file is part of Privacy Browser Android . * @@ -23,7 +23,6 @@ import android.annotation.SuppressLint import android.app.Application import android.content.ContentResolver import android.graphics.Typeface -import android.net.Uri import android.text.SpannableStringBuilder import android.text.Spanned import android.text.style.StyleSpan @@ -52,6 +51,7 @@ import javax.net.ssl.SSLContext import javax.net.ssl.SSLSession import javax.net.ssl.TrustManager import javax.net.ssl.X509TrustManager +import androidx.core.net.toUri class GetHeadersBackgroundTask { @@ -76,7 +76,7 @@ class GetHeadersBackgroundTask { // Attempt to read the content data. Return an error if this fails. try { // Get a URI for the content URL. - val contentUri = Uri.parse(urlString) + val contentUri = urlString.toUri() // Get a cursor with metadata about the content URL. val contentCursor = contentResolver.query(contentUri, null, null, null, null)!! @@ -350,7 +350,7 @@ class GetHeadersBackgroundTask { // Populate the SSL certificate, returned separately. sslCertificateBuilder.append(serverCertificate.toString()) - } catch (exception: Exception) { + } catch (_: Exception) { // Do nothing. } diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutVersionFragment.kt b/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutVersionFragment.kt index cc0b19ed..cc3dcf5f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutVersionFragment.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/AboutVersionFragment.kt @@ -19,7 +19,6 @@ package com.stoutner.privacybrowser.fragments -import android.annotation.SuppressLint import android.app.Activity import android.app.ActivityManager import android.content.ClipData @@ -536,10 +535,8 @@ class AboutVersionFragment : Fragment() { // Display the package signature. try { - // Get the first package signature. Suppress the lint warning about the need to be careful in implementing comparison of certificates for security purposes. - // Once the minimum API >= 28, `GET_SIGNING_CERTIFICATES` can be used instead. Once the minimum API >= 33, the newer `getPackageInfo()` may be used. - @Suppress("DEPRECATION") - @SuppressLint("PackageManagerGetSignatures") val packageSignature = requireContext().packageManager.getPackageInfo(requireContext().packageName,PackageManager.GET_SIGNATURES).signatures!![0] + // Get the first package signature. + val packageSignature = requireContext().packageManager.getPackageInfo(requireContext().packageName,PackageManager.GET_SIGNING_CERTIFICATES).signingInfo!!.apkContentsSigners[0] // Convert the signature to a byte array input stream. val certificateByteArrayInputStream: InputStream = ByteArrayInputStream(packageSignature.toByteArray()) diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.kt b/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.kt index 14449340..53c9c1d1 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.kt @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later - * SPDX-FileCopyrightText: 2016-2025 Soren Stoutner + * SPDX-FileCopyrightText: 2016-2026 Soren Stoutner * * This file is part of Privacy Browser Android . * @@ -1047,14 +1047,8 @@ class SettingsFragment : PreferenceFragmentCompat() { // Update the theme preference summary text. appThemePreference.summary = appThemeEntriesStringArray[0] - // Apply the new theme. - if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported. - // Follow the system default theme. - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) - } else { // The system default theme is not supported. - // Follow the battery saver mode. - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY) - } + // Follow the system default theme. + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) } 1 -> { // The light theme is selected. diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.kt b/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.kt index 4b25e134..e795940a 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.kt @@ -88,11 +88,6 @@ class ImportExportDatabaseHelper { // Create a temporary import file. val temporaryImportFile = File.createTempFile("temporary_import_file", null, context.cacheDir) - // The file may be copied directly in Kotlin using `File.copyTo`. - // It can be copied in Android using `Files.copy` once the minimum API >= 26. - // - // However, the file cannot be acquired from the content URI until the minimum API >= 29. - // Create a temporary file output stream. val temporaryImportFileOutputStream = FileOutputStream(temporaryImportFile) @@ -118,7 +113,7 @@ class ImportExportDatabaseHelper { // Get a handle for the shared preference. val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - // Open the import database. Once the minimum API >= 27 the file can be opened directly without using the string. + // Open the import database. val importDatabase = SQLiteDatabase.openDatabase(temporaryImportFile.toString(), null, SQLiteDatabase.OPEN_READWRITE) // Get the database version. @@ -1072,12 +1067,6 @@ class ImportExportDatabaseHelper { // Close the temporary export database. temporaryExportDatabase.close() - - // The file may be copied directly in Kotlin using `File.copyTo`. - // It can be copied in Android using `Files.copy` once the minimum API >= 26. - // - // However, the file cannot be acquired from the content URI until the minimum API >= 29. - // Create the temporary export file input stream. val temporaryExportFileInputStream = FileInputStream(temporaryExportFile) diff --git a/build.gradle b/build.gradle index 01dec7df..ba456754 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:9.1.0' + classpath 'com.android.tools.build:gradle:9.2.0' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.10' // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 302f2947..8c0cbb58 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -20,4 +20,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip