X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Fcoroutines%2FSaveUrlCoroutine.kt;h=f8adc5b0f187862fbd611cab2d373becaad2645e;hb=e065315a36c804626a7dba38d3edad05e9fdb473;hp=c6fd36a284478ff7e6bdfcd38e0267829572257e;hpb=5186b668274b09e37b371c0a134e53255c98ad98;p=PrivacyBrowserAndroid.git diff --git a/app/src/main/java/com/stoutner/privacybrowser/coroutines/SaveUrlCoroutine.kt b/app/src/main/java/com/stoutner/privacybrowser/coroutines/SaveUrlCoroutine.kt index c6fd36a2..f8adc5b0 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/coroutines/SaveUrlCoroutine.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/coroutines/SaveUrlCoroutine.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-2023 Soren Stoutner . + * Copyright 2020-2024 Soren Stoutner . * * This file is part of Privacy Browser Android . * @@ -22,16 +22,16 @@ package com.stoutner.privacybrowser.coroutines import android.app.Activity import android.content.Context import android.net.Uri -import android.os.Build import android.provider.OpenableColumns import android.util.Base64 import android.webkit.CookieManager +import androidx.viewpager2.widget.ViewPager2 + import com.google.android.material.snackbar.Snackbar import com.stoutner.privacybrowser.R import com.stoutner.privacybrowser.helpers.ProxyHelper -import com.stoutner.privacybrowser.views.NoSwipeViewPager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -43,37 +43,33 @@ import java.io.InputStream import java.net.HttpURLConnection import java.net.URL import java.text.NumberFormat +import java.util.Date class SaveUrlCoroutine { fun save(context: Context, activity: Activity, urlString: String, fileUri: Uri, userAgent: String, cookiesEnabled: Boolean) { + // Create a canceled boolean. + var canceled = false + // Use a coroutine to save the URL. CoroutineScope(Dispatchers.Main).launch { - // Create a file name string. - val fileNameString: String + // Get a cursor from the content resolver. + val contentResolverCursor = activity.contentResolver.query(fileUri, null, null, null)!! - // Query the exact file name if the API >= 26. - if (Build.VERSION.SDK_INT >= 26) { - // Get a cursor from the content resolver. - val contentResolverCursor = activity.contentResolver.query(fileUri, null, null, null)!! + // Move to the first row. + contentResolverCursor.moveToFirst() - // Move to the first row. - contentResolverCursor.moveToFirst() + // Get the file name from the cursor. + val fileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)) - // Get the file name from the cursor. - fileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)) - - // Close the cursor. - contentResolverCursor.close() - } else { - // Use the file URI last path segment as the file name string. - fileNameString = fileUri.lastPathSegment!! - } + // Close the cursor. + contentResolverCursor.close() // Get a handle for the no swipe view pager. - val noSwipeViewPager = activity.findViewById(R.id.webviewpager) + val webViewViewPager2 = activity.findViewById(R.id.webview_viewpager2) // Create a saving file snackbar. - val savingFileSnackbar = Snackbar.make(noSwipeViewPager, activity.getString(R.string.saving_file, 0, fileNameString), Snackbar.LENGTH_INDEFINITE) + val savingFileSnackbar = Snackbar.make(webViewViewPager2, activity.getString(R.string.saving_file, 0, fileNameString), Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.cancel) { canceled = true } // Display the saving file snackbar. savingFileSnackbar.show() @@ -149,40 +145,52 @@ class SaveUrlCoroutine { val inputStream: InputStream = BufferedInputStream(httpUrlConnection.inputStream) // Initialize the conversion buffer byte array. - // This is set to a megabyte so that frequent updating of the snackbar doesn't freeze the interface on download. - val conversionBufferByteArray = ByteArray(1048576) + // This is set to a 50,000 bytes so that frequent updating of the snackbar doesn't freeze the interface on download, although `inputStream.read` currently uses 8,000 as an upper limit. + // + val conversionBufferByteArray = ByteArray(50_000) - // Initialize the downloaded kilobytes counter. - var downloadedKilobytesCounter: Long = 0 + // Initialize the longs. + var downloadedBytesCounterLong: Long = 0 + var lastSnackbarUpdateLong: Long = 0 // Define the buffer length variable. var bufferLength: Int // Attempt to read data from the input stream and store it in the output stream. Also store the amount of data read in the buffer length variable. - while (inputStream.read(conversionBufferByteArray).also { bufferLength = it } > 0) { // Proceed while the amount of data stored in the buffer in > 0. + while ((inputStream.read(conversionBufferByteArray).also { bufferLength = it } > 0) && !canceled) { // Proceed while the amount of data stored in the buffer in > 0. // Write the contents of the conversion buffer to the file output stream. outputStream.write(conversionBufferByteArray, 0, bufferLength) - // Update the downloaded kilobytes counter. - downloadedKilobytesCounter += bufferLength + // Update the downloaded bytes counter. + downloadedBytesCounterLong += bufferLength // Format the number of bytes downloaded. - val formattedNumberOfBytesDownloadedString = NumberFormat.getInstance().format(downloadedKilobytesCounter) - - // Update the UI. - withContext(Dispatchers.Main) { - // Check to see if the file size is known. - if (fileSize == -1L) { // The size of the download file is not known. - // Update the snackbar. - savingFileSnackbar.setText(activity.getString(R.string.saving_file_progress, formattedNumberOfBytesDownloadedString, fileNameString)) - } else { // The size of the download file is known. - // Calculate the download percentage. - val downloadPercentage = downloadedKilobytesCounter * 100 / fileSize - - // Update the snackbar. - savingFileSnackbar.setText(activity.getString(R.string.saving_file_percentage_progress, downloadPercentage, formattedNumberOfBytesDownloadedString, formattedFileSize, - fileNameString) - ) + val formattedNumberOfBytesDownloadedString = NumberFormat.getInstance().format(downloadedBytesCounterLong) + + // Get the current time. + val currentTimeLong = Date().time + + // Update the snackbar if more than 100 milliseconds have passed since the last update. + // Updating the snackbar is so resource intensive that it will throttle the download if it is done too frequently. + if (currentTimeLong - lastSnackbarUpdateLong > 100) { + // Store the update time. + lastSnackbarUpdateLong = currentTimeLong + + // Update the UI. + withContext(Dispatchers.Main) { + // Check to see if the file size is known. + if (fileSize == -1L) { // The size of the download file is not known. + // Update the snackbar. + savingFileSnackbar.setText(activity.getString(R.string.saving_file_progress, formattedNumberOfBytesDownloadedString, fileNameString)) + } else { // The size of the download file is known. + // Calculate the download percentage. + val downloadPercentage = downloadedBytesCounterLong * 100 / fileSize + + // Update the snackbar. + savingFileSnackbar.setText(activity.getString(R.string.saving_file_percentage_progress, downloadPercentage, formattedNumberOfBytesDownloadedString, formattedFileSize, + fileNameString) + ) + } } } } @@ -203,8 +211,13 @@ class SaveUrlCoroutine { // Dismiss the saving file snackbar. savingFileSnackbar.dismiss() - // Display the file saved snackbar. - Snackbar.make(noSwipeViewPager, activity.getString(R.string.saved, fileNameString), Snackbar.LENGTH_LONG).show() + // Display a final disposition snackbar. + if (canceled) + // Display the download cancelled snackbar. + Snackbar.make(webViewViewPager2, activity.getString(R.string.download_cancelled), Snackbar.LENGTH_SHORT).show() + else + // Display the file saved snackbar. + Snackbar.make(webViewViewPager2, activity.getString(R.string.saved, fileNameString), Snackbar.LENGTH_LONG).show() } } catch (exception: Exception) { // Update the UI. @@ -213,10 +226,10 @@ class SaveUrlCoroutine { savingFileSnackbar.dismiss() // Display the file saving error. - Snackbar.make(noSwipeViewPager, activity.getString(R.string.error_saving_file, fileNameString, exception), Snackbar.LENGTH_INDEFINITE).show() + Snackbar.make(webViewViewPager2, activity.getString(R.string.error_saving_file, fileNameString, exception), Snackbar.LENGTH_INDEFINITE).show() } } } } } -} \ No newline at end of file +}