2 * Copyright © 2020-2021 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
6 * Privacy Browser 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.
11 * Privacy Browser 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.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.asynctasks;
22 import android.app.Activity;
23 import android.graphics.Bitmap;
24 import android.graphics.Canvas;
25 import android.net.Uri;
26 import android.os.AsyncTask;
27 import android.widget.LinearLayout;
29 import com.google.android.material.snackbar.Snackbar;
31 import com.stoutner.privacybrowser.R;
33 import java.io.ByteArrayOutputStream;
34 import java.io.OutputStream;
35 import java.lang.ref.WeakReference;
37 public class SaveAboutVersionImage extends AsyncTask<Void, Void, String> {
38 // Declare the weak references.
39 private final WeakReference<Activity> activityWeakReference;
40 private final WeakReference<LinearLayout> aboutVersionLinearLayoutWeakReference;
42 // Declare the class constants.
43 private final String SUCCESS = "Success";
45 // Declare the class variables.
46 private Snackbar savingImageSnackbar;
47 private Bitmap aboutVersionBitmap;
48 private final String fileNameString;
50 // The public constructor.
51 public SaveAboutVersionImage(Activity activity, String fileNameString, LinearLayout aboutVersionLinearLayout) {
52 // Populate the weak references.
53 activityWeakReference = new WeakReference<>(activity);
54 aboutVersionLinearLayoutWeakReference = new WeakReference<>(aboutVersionLinearLayout);
56 // Store the class variables.
57 this.fileNameString = fileNameString;
60 // `onPreExecute()` operates on the UI thread.
62 protected void onPreExecute() {
63 // Get handles for the activity and the linear layout.
64 Activity activity = activityWeakReference.get();
65 LinearLayout aboutVersionLinearLayout = aboutVersionLinearLayoutWeakReference.get();
67 // Abort if the activity or the linear layout is gone.
68 if ((activity == null) || activity.isFinishing() || aboutVersionLinearLayout == null) {
72 // Create a saving image snackbar.
73 savingImageSnackbar = Snackbar.make(aboutVersionLinearLayout, activity.getString(R.string.processing_image) + " " + fileNameString, Snackbar.LENGTH_INDEFINITE);
75 // Display the saving image snackbar.
76 savingImageSnackbar.show();
78 // Create the about version bitmap. This can be replaced by PixelCopy once the minimum API >= 26.
79 // 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.
80 aboutVersionBitmap = Bitmap.createBitmap(aboutVersionLinearLayout.getWidth(), aboutVersionLinearLayout.getHeight(), Bitmap.Config.ARGB_8888);
83 Canvas aboutVersionCanvas = new Canvas(aboutVersionBitmap);
85 // Draw the current about version onto the bitmap. The linear layout commands must be run on the UI thread.
86 aboutVersionLinearLayout.draw(aboutVersionCanvas);
90 protected String doInBackground(Void... Void) {
91 // Get a handle for the activity.
92 Activity activity = activityWeakReference.get();
94 // Abort if the activity is gone.
95 if (((activity == null) || activity.isFinishing())) {
99 // Create an about version PNG byte array output stream.
100 ByteArrayOutputStream aboutVersionByteArrayOutputStream = new ByteArrayOutputStream();
102 // 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.
103 aboutVersionBitmap.compress(Bitmap.CompressFormat.PNG, 0, aboutVersionByteArrayOutputStream);
105 // Create a file creation disposition string.
106 String fileCreationDisposition = SUCCESS;
109 // Open an output stream.
110 OutputStream outputStream = activity.getContentResolver().openOutputStream(Uri.parse(fileNameString));
112 // Write the webpage image to the image file.
113 aboutVersionByteArrayOutputStream.writeTo(outputStream);
115 // Flush the output stream.
116 outputStream.flush();
118 // Close the output stream.
119 outputStream.close();
120 } catch (Exception exception) {
121 // Store the error in the file creation disposition string.
122 fileCreationDisposition = exception.toString();
125 // return the file creation disposition string.
126 return fileCreationDisposition;
129 // `onPostExecute()` operates on the UI thread.
131 protected void onPostExecute(String fileCreationDisposition) {
132 // Get handles for the weak references.
133 Activity activity = activityWeakReference.get();
134 LinearLayout aboutVersionLinearLayout = aboutVersionLinearLayoutWeakReference.get();
136 // Abort if the activity is gone.
137 if ((activity == null) || activity.isFinishing()) {
141 // Dismiss the saving image snackbar.
142 savingImageSnackbar.dismiss();
144 // Display a file creation disposition snackbar.
145 if (fileCreationDisposition.equals(SUCCESS)) {
146 // Create a file saved snackbar.
147 Snackbar.make(aboutVersionLinearLayout, activity.getString(R.string.file_saved) + " " + fileNameString, Snackbar.LENGTH_SHORT).show();
149 Snackbar.make(aboutVersionLinearLayout, activity.getString(R.string.error_saving_file) + " " + fileCreationDisposition, Snackbar.LENGTH_INDEFINITE).show();