]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveWebpageImage.java
aeb92988e93f52aedfe2b573cc15d77c3922ace6
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / asynctasks / SaveWebpageImage.java
1 /*
2  * Copyright © 2019 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 package com.stoutner.privacybrowser.asynctasks;
21
22 import android.app.Activity;
23 import android.graphics.Bitmap;
24 import android.graphics.Canvas;
25 import android.os.AsyncTask;
26
27 import com.google.android.material.snackbar.Snackbar;
28
29 import com.stoutner.privacybrowser.R;
30 import com.stoutner.privacybrowser.views.NestedScrollWebView;
31 import com.stoutner.privacybrowser.views.NoSwipeViewPager;
32
33 import java.io.ByteArrayOutputStream;
34 import java.io.File;
35 import java.io.FileOutputStream;
36 import java.lang.ref.WeakReference;
37
38 public class SaveWebpageImage extends AsyncTask<String, Void, String> {
39     // Define the weak references.
40     private WeakReference<Activity> activityWeakReference;
41     private WeakReference<NestedScrollWebView> nestedScrollWebViewWeakReference;
42
43     // Define a success string constant.
44     private final String SUCCESS = "Success";
45
46     // Define the saving image snackbar and the webpage bitmap.
47     private Snackbar savingImageSnackbar;
48     private Bitmap webpageBitmap;
49
50     // The public constructor.
51     public SaveWebpageImage(Activity activity, NestedScrollWebView nestedScrollWebView) {
52         // Populate the weak references.
53         activityWeakReference = new WeakReference<>(activity);
54         nestedScrollWebViewWeakReference = new WeakReference<>(nestedScrollWebView);
55     }
56
57     // `onPreExecute()` operates on the UI thread.
58     @Override
59     protected void onPreExecute() {
60         // Get a handle for the activity and the nested scroll WebView.
61         Activity activity = activityWeakReference.get();
62         NestedScrollWebView nestedScrollWebView = nestedScrollWebViewWeakReference.get();
63
64         // Abort if the activity or the nested scroll WebView is gone.
65         if ((activity == null) || activity.isFinishing() || nestedScrollWebView == null) {
66             return;
67         }
68
69         // Create a saving image snackbar.
70         savingImageSnackbar = Snackbar.make(nestedScrollWebView, R.string.saving_image, Snackbar.LENGTH_INDEFINITE);
71
72         // Display the saving image snackbar.
73         savingImageSnackbar.show();
74
75         // Create a webpage bitmap.  Once the Minimum API >= 26 Bitmap.Config.RBGA_F16 can be used instead of ARGB_8888.  The nested scroll WebView commands must be run on the UI thread.
76         webpageBitmap = Bitmap.createBitmap(nestedScrollWebView.getHorizontalScrollRange(), nestedScrollWebView.getVerticalScrollRange(), Bitmap.Config.ARGB_8888);
77
78         // Create a canvas.
79         Canvas webpageCanvas = new Canvas(webpageBitmap);
80
81         // Draw the current webpage onto the bitmap.  The nested scroll WebView commands must be run on the UI thread.
82         nestedScrollWebView.draw(webpageCanvas);
83     }
84
85     @Override
86     protected String doInBackground(String... fileName) {
87         // Get a handle for the activity.
88         Activity activity = activityWeakReference.get();
89
90         // Abort if the activity is gone.
91         if ((activity == null) || activity.isFinishing()) {
92             return "";
93         }
94
95         // Create a webpage PNG byte array output stream.
96         ByteArrayOutputStream webpageByteArrayOutputStream = new ByteArrayOutputStream();
97
98         // Convert the bitmap to a PNG.  `0` is for lossless compression (the only option for a PNG).  This compression takes a long time.
99         webpageBitmap.compress(Bitmap.CompressFormat.PNG, 0, webpageByteArrayOutputStream);
100
101         // Get a file for the image.
102         File imageFile = new File(fileName[0]);
103
104         // Delete the current file if it exists.
105         if (imageFile.exists()) {
106             //noinspection ResultOfMethodCallIgnored
107             imageFile.delete();
108         }
109
110         // Create a file creation disposition string.
111         String fileCreationDisposition = SUCCESS;
112
113         try {
114             // Create an image file output stream.
115             FileOutputStream imageFileOutputStream = new FileOutputStream(imageFile);
116
117             // Write the webpage image to the image file.
118             webpageByteArrayOutputStream.writeTo(imageFileOutputStream);
119         } catch (Exception exception) {
120             // Store the error in the file creation disposition string.
121             fileCreationDisposition = exception.toString();
122         }
123
124         // Return the file creation disposition string.
125         return fileCreationDisposition;
126     }
127
128     // `onPostExecute()` operates on the UI thread.
129     @Override
130     protected void onPostExecute(String fileCreationDisposition) {
131         // Get a handle for the activity.
132         Activity activity = activityWeakReference.get();
133
134         // Abort if the activity is gone.
135         if ((activity == null) || activity.isFinishing()) {
136             return;
137         }
138
139         // Get a handle for the no swipe view pager.
140         NoSwipeViewPager noSwipeViewPager = activity.findViewById(R.id.webviewpager);
141
142         // Dismiss the saving image snackbar.
143         savingImageSnackbar.dismiss();
144
145         // Display a file creation disposition snackbar.
146         if (fileCreationDisposition.equals(SUCCESS)) {
147             Snackbar.make(noSwipeViewPager, R.string.image_saved, Snackbar.LENGTH_SHORT).show();
148         } else {
149             Snackbar.make(noSwipeViewPager, activity.getString(R.string.error_saving_image) + "  " + fileCreationDisposition, Snackbar.LENGTH_INDEFINITE).show();
150         }
151     }
152 }