fd72db47463448261a297c7dc93fb20aa32379ec
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / asynctasks / SaveUrl.java
1 /*
2  * Copyright © 2020 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.os.AsyncTask;
24 import android.webkit.CookieManager;
25
26 import com.google.android.material.snackbar.Snackbar;
27 import com.stoutner.privacybrowser.R;
28 import com.stoutner.privacybrowser.views.NoSwipeViewPager;
29
30 import java.io.BufferedInputStream;
31 import java.io.File;
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.lang.ref.WeakReference;
37 import java.net.HttpURLConnection;
38 import java.net.URL;
39
40 public class SaveUrl extends AsyncTask<String, Void, String> {
41     // Define a weak reference to the calling activity.
42     private WeakReference<Activity> activityWeakReference;
43
44     // Define a success string constant.
45     private final String SUCCESS = "Success";
46
47     // Define the class variables.
48     private String filePathString;
49     private String userAgent;
50     private boolean cookiesEnabled;
51     private Snackbar savingFileSnackbar;
52
53     // The public constructor.
54     public SaveUrl(Activity activity, String filePathString, String userAgent, boolean cookiesEnabled) {
55         // Populate the weak reference to the calling activity.
56         activityWeakReference = new WeakReference<>(activity);
57
58         // Store the class variables.
59         this.filePathString = filePathString;
60         this.userAgent = userAgent;
61         this.cookiesEnabled = cookiesEnabled;
62     }
63
64     // `onPreExecute()` operates on the UI thread.
65     @Override
66     protected void onPreExecute() {
67         // Get a handle for the activity.
68         Activity activity = activityWeakReference.get();
69
70         // Abort if the activity is gone.
71         if ((activity==null) || activity.isFinishing()) {
72             return;
73         }
74
75         // Get a handle for the no swipe view pager.
76         NoSwipeViewPager noSwipeViewPager = activity.findViewById(R.id.webviewpager);
77
78         // Create a saving file snackbar.
79         savingFileSnackbar = Snackbar.make(noSwipeViewPager, R.string.saving_file, Snackbar.LENGTH_INDEFINITE);
80
81         // Display the saving file snackbar.
82         savingFileSnackbar.show();
83     }
84
85     @Override
86     protected String doInBackground(String... urlToSave) {
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 null;
93         }
94
95         // Define a save disposition string.
96         String saveDisposition = SUCCESS;
97
98         // Because everything relating to requesting data from a webserver can throw errors, the entire section must catch `IOExceptions`.
99         try {
100             // Get the URL from the main activity.
101             URL url = new URL(urlToSave[0]);
102
103             // Open a connection to the URL.  No data is actually sent at this point.
104             HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
105
106             // Add the user agent to the header property.
107             httpUrlConnection.setRequestProperty("User-Agent", userAgent);
108
109             // Add the cookies if they are enabled.
110             if (cookiesEnabled) {
111                 // Get the cookies for the current domain.
112                 String cookiesString = CookieManager.getInstance().getCookie(url.toString());
113
114                 // Only add the cookies if they are not null.
115                 if (cookiesString != null) {
116                     // Add the cookies to the header property.
117                     httpUrlConnection.setRequestProperty("Cookie", cookiesString);
118                 }
119             }
120
121             // The actual network request is in a `try` bracket so that `disconnect()` is run in the `finally` section even if an error is encountered in the main block.
122             try {
123                 // Get the response code, which causes the connection to the server to be made.
124                 httpUrlConnection.getResponseCode();
125
126                 // Get the response body stream.
127                 InputStream inputStream = new BufferedInputStream(httpUrlConnection.getInputStream());
128
129                 // Get the file.
130                 File file = new File(filePathString);
131
132                 // Delete the file if it exists.
133                 if (file.exists()) {
134                     //noinspection ResultOfMethodCallIgnored
135                     file.delete();
136                 }
137
138                 // Create a new file.
139                 //noinspection ResultOfMethodCallIgnored
140                 file.createNewFile();
141
142                 // Create an output file stream.
143                 OutputStream outputStream = new FileOutputStream(file);
144
145                 // Initialize the conversion buffer byte array.
146                 byte[] conversionBufferByteArray = new byte[1024];
147
148                 // Define the buffer length variable.
149                 int bufferLength;
150
151                 // 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.
152                 while ((bufferLength = inputStream.read(conversionBufferByteArray)) > 0) {  // Proceed while the amount of data stored in the buffer in > 0.
153                     // Write the contents of the conversion buffer to the output stream.
154                     outputStream.write(conversionBufferByteArray, 0, bufferLength);
155                 }
156
157                 // Close the input stream.
158                 inputStream.close();
159
160                 // Close the output stream.
161                 outputStream.close();
162             } finally {
163                 // Disconnect the HTTP URL connection.
164                 httpUrlConnection.disconnect();
165             }
166         } catch (IOException exception) {
167             // Store the error in the save disposition string.
168             saveDisposition = exception.toString();
169         }
170
171         // Return the save disposition string.
172         return saveDisposition;
173     }
174
175     // `onPostExecute()` operates on the UI thread.
176     @Override
177     protected void onPostExecute(String saveDisposition) {
178         // Get a handle for the activity.
179         Activity activity = activityWeakReference.get();
180
181         // Abort if the activity is gone.
182         if ((activity == null) || activity.isFinishing()) {
183             return;
184         }
185
186         // Get a handle for the no swipe view pager.
187         NoSwipeViewPager noSwipeViewPager = activity.findViewById(R.id.webviewpager);
188
189         // Dismiss the saving file snackbar.
190         savingFileSnackbar.dismiss();
191
192         // Display a save disposition snackbar.
193         if (saveDisposition.equals(SUCCESS)) {
194             Snackbar.make(noSwipeViewPager, R.string.file_saved, Snackbar.LENGTH_SHORT).show();
195         } else {
196             Snackbar.make(noSwipeViewPager, activity.getString(R.string.error_saving_file) + "  " + saveDisposition, Snackbar.LENGTH_INDEFINITE).show();
197         }
198     }
199 }