X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Fasynctasks%2FSaveAboutVersionImage.java;fp=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Fasynctasks%2FSaveAboutVersionImage.java;h=eda5726c49c5e92c0a5b638333af042924044dda;hb=1003c7842a01f338c8aaf9d4f07216111f294202;hp=0000000000000000000000000000000000000000;hpb=4196bafc4069857b554ac95addcae92fcabae901;p=PrivacyBrowserAndroid.git diff --git a/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveAboutVersionImage.java b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveAboutVersionImage.java new file mode 100644 index 00000000..eda5726c --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveAboutVersionImage.java @@ -0,0 +1,209 @@ +/* + * Copyright © 2020 Soren Stoutner . + * + * This file is part of Privacy Browser . + * + * Privacy Browser is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser. If not, see . + */ + +package com.stoutner.privacybrowser.asynctasks; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.core.content.FileProvider; + +import com.google.android.material.snackbar.Snackbar; + +import com.stoutner.privacybrowser.R; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.lang.ref.WeakReference; + +public class SaveAboutVersionImage extends AsyncTask { + // Declare the weak references. + private WeakReference contextWeakReference; + private WeakReference activityWeakReference; + private WeakReference aboutVersionLinearLayoutWeakReference; + + // Declare the class constants. + private final String SUCCESS = "Success"; + + // Declare the class variables. + private Snackbar savingImageSnackbar; + private Bitmap aboutVersionBitmap; + private String filePathString; + + // The public constructor. + public SaveAboutVersionImage(Context context, Activity activity, String filePathString, LinearLayout aboutVersionLinearLayout) { + // Populate the weak references. + contextWeakReference = new WeakReference<>(context); + activityWeakReference = new WeakReference<>(activity); + aboutVersionLinearLayoutWeakReference = new WeakReference<>(aboutVersionLinearLayout); + + // Store the class variables. + this.filePathString = filePathString; + } + + // `onPreExecute()` operates on the UI thread. + @Override + protected void onPreExecute() { + // Get handles for the activity and the linear layout. + Activity activity = activityWeakReference.get(); + LinearLayout aboutVersionLinearLayout = aboutVersionLinearLayoutWeakReference.get(); + + // Abort if the activity or the linear layout is gone. + if ((activity == null) || activity.isFinishing() || aboutVersionLinearLayout == null) { + return; + } + + // Create a saving image snackbar. + savingImageSnackbar = Snackbar.make(aboutVersionLinearLayout, activity.getString(R.string.processing_image) + " " + filePathString, Snackbar.LENGTH_INDEFINITE); + + // Display the saving image snackbar. + savingImageSnackbar.show(); + + // Create the about version bitmap. This can be replaced by PixelCopy once the minimum API >= 26. + // Once the Minimum API >= 26 Bitmap.Config.RBGA_F16 can be used instead of ARGB_8888. The linear layout commands must be run on the UI thread. + aboutVersionBitmap = Bitmap.createBitmap(aboutVersionLinearLayout.getWidth(), aboutVersionLinearLayout.getHeight(), Bitmap.Config.ARGB_8888); + + // Create a canvas. + Canvas aboutVersionCanvas = new Canvas(aboutVersionBitmap); + + // Draw the current about version onto the bitmap. The linear layout commands must be run on the UI thread. + aboutVersionLinearLayout.draw(aboutVersionCanvas); + } + + @Override + protected String doInBackground(Void... Void) { + // Get a handle for the activity. + Activity activity = activityWeakReference.get(); + + // Abort if the activity is gone. + if (((activity == null) || activity.isFinishing())) { + return ""; + } + + // Create an about version PNG byte array output stream. + ByteArrayOutputStream aboutVersionByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the bitmap to a PNG. `0` is for lossless compression (the only option for a PNG). This compression takes a long time. Once the minimum API >= 30 this could be replaced with WEBP_LOSSLESS. + aboutVersionBitmap.compress(Bitmap.CompressFormat.PNG, 0, aboutVersionByteArrayOutputStream); + + // Get a file for the image. + File imageFile = new File(filePathString); + + // Delete the current file if it exists. + if (imageFile.exists()) { + //noinspection ResultOfMethodCallIgnored + imageFile.delete(); + } + + // Create a file creation disposition string. + String fileCreationDisposition = SUCCESS; + + try { + // Create an image file output stream. + FileOutputStream imageFileOutputStream = new FileOutputStream(imageFile); + + // Write the webpage image to the image file. + aboutVersionByteArrayOutputStream.writeTo(imageFileOutputStream); + + // Create a media scanner intent, which adds items like pictures to Android's recent file list. + Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + + // Add the URI to the media scanner intent. + mediaScannerIntent.setData(Uri.fromFile(imageFile)); + + // Make it so. + activity.sendBroadcast(mediaScannerIntent); + } catch (Exception exception) { + // Store the error in the file creation disposition string. + fileCreationDisposition = exception.toString(); + } + + // return the file creation disposition string. + return fileCreationDisposition; + } + + // `onPostExecute()` operates on the UI thread. + @Override + protected void onPostExecute(String fileCreationDisposition) { + // Get handles for the weak references. + Context context = contextWeakReference.get(); + Activity activity = activityWeakReference.get(); + LinearLayout aboutVersionLinearLayout = aboutVersionLinearLayoutWeakReference.get(); + + // Abort if the activity is gone. + if ((activity == null) || activity.isFinishing()) { + return; + } + + // Dismiss the saving image snackbar. + savingImageSnackbar.dismiss(); + + // Display a file creation disposition snackbar. + if (fileCreationDisposition.equals(SUCCESS)) { + // Create a file saved snackbar. + Snackbar imageSavedSnackbar = Snackbar.make(aboutVersionLinearLayout, activity.getString(R.string.file_saved) + " " + filePathString, Snackbar.LENGTH_SHORT); + + // Add an open action. + imageSavedSnackbar.setAction(R.string.open, (View view) -> { + // Get a file for the file path string. + File file = new File(filePathString); + + // Declare a file URI variable. + Uri fileUri; + + // Get the URI for the file according to the Android version. + if (Build.VERSION.SDK_INT >= 24) { // Use a file provider. + fileUri = FileProvider.getUriForFile(context, activity.getString(R.string.file_provider), file); + } else { // Get the raw file path URI. + fileUri = Uri.fromFile(file); + } + + // Get a handle for the content resolver. + ContentResolver contentResolver = context.getContentResolver(); + + // Create an open intent with `ACTION_VIEW`. + Intent openIntent = new Intent(Intent.ACTION_VIEW); + + // Autodetect the MIME type. + openIntent.setDataAndType(fileUri, contentResolver.getType(fileUri)); + + // Allow the app to read the file URI. + openIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + + // Show the chooser. + activity.startActivity(Intent.createChooser(openIntent, context.getString(R.string.open))); + }); + + // Show the image saved snackbar. + imageSavedSnackbar.show(); + } else { + Snackbar.make(aboutVersionLinearLayout, activity.getString(R.string.error_saving_file) + " " + fileCreationDisposition, Snackbar.LENGTH_INDEFINITE).show(); + } + } +} \ No newline at end of file