3b448bd666f0e75b6fd84902884e4abe3aa5f0a1
[PrivacyCell.git] / app / src / main / java / com / stoutner / privacycell / dialogs / WebViewDialog.kt
1 /*
2  * Copyright © 2021 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>.
5  *
6  * Privacy Cell 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 Cell 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 Cell.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacycell.dialogs
21
22 import android.app.Dialog
23 import android.content.Intent
24 import android.content.res.Configuration
25 import android.os.Bundle
26 import android.webkit.WebResourceRequest
27 import android.webkit.WebResourceResponse
28 import android.webkit.WebView
29 import android.webkit.WebViewClient
30
31 import androidx.appcompat.app.AlertDialog
32 import androidx.fragment.app.DialogFragment
33 import androidx.webkit.WebSettingsCompat
34 import androidx.webkit.WebViewAssetLoader
35 import androidx.webkit.WebViewFeature
36
37 import com.stoutner.privacycell.R
38
39 // Define the class constants.
40 private const val DIALOG_TYPE = "dialog_type"
41 private const val SCROLL_Y = "scroll_y"
42
43 class WebViewDialog : DialogFragment() {
44     companion object {
45         // Define the public constants.
46         const val PERMISSIONS = 0
47         const val PRIVACY_POLICY = 1
48         const val CHANGELOG = 2
49         const val LICENSES = 3
50         const val CONTRIBUTORS = 4
51         const val STINGRAY = 5
52         const val NETWORK_UNKNOWN = 6
53         const val NETWORK_GPRS = 7
54         const val NETWORK_EDGE = 8
55         const val NETWORK_UMTS = 9
56         const val NETWORK_CDMA = 10
57         const val NETWORK_EVDO_0 = 11
58         const val NETWORK_EVDO_A = 12
59         const val NETWORK_1xRTT = 13
60         const val NETWORK_HSDPA = 14
61         const val NETWORK_HSUPA = 15
62         const val NETWORK_HSPA = 16
63         const val NETWORK_IDEN = 17
64         const val NETWORK_EVDO_B = 18
65         const val NETWORK_LTE = 19
66         const val NETWORK_EHRPD = 20
67         const val NETWORK_HSPAP = 21
68         const val NETWORK_GSM = 22
69         const val NETWORK_TD_SCDMA = 23
70         const val NETWORK_IWLAN = 24
71         const val NETWORK_NR = 25
72         const val OVERRIDE_NETWORK_NONE = 26
73         const val OVERRIDE_NETWORK_LTE_CA = 27
74         const val OVERRIDE_NETWORK_LTE_ADVANCED_PRO = 28
75         const val OVERRIDE_NETWORK_NR_NSA = 29
76         const val OVERRIDE_NETWORK_NR_NSA_MMWAVE = 30
77     }
78
79     // Define the class views.
80     private lateinit var webView: WebView
81
82     // Populate the WebView dialog type.
83     fun type(dialogType: Int): WebViewDialog {
84         // Create an arguments bundle.
85         val argumentsBundle = Bundle()
86
87         // Add the dialog type to the bundle.
88         argumentsBundle.putInt(DIALOG_TYPE, dialogType)
89
90         // Create a new instance of the WebView dialog.
91         val webViewDialog = WebViewDialog()
92
93         // Add the arguments bundle to the new dialog.
94         webViewDialog.arguments = argumentsBundle
95
96         // Return the new dialog.
97         return webViewDialog
98     }
99
100     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
101         // Get the dialog type from the arguments bundle.
102         val dialogType = requireArguments().getInt(DIALOG_TYPE)
103
104         // Use a builder to create the alert dialog.
105         val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.Theme_PrivacyCellAlertDialog)
106
107         // Set the icon and the title according to the dialog type.
108         when (dialogType) {
109             PERMISSIONS -> {
110                 // Set the icon.
111                 dialogBuilder.setIcon(R.drawable.permissions)
112
113                 // Set the title.
114                 dialogBuilder.setTitle(R.string.permissions)
115             }
116
117             PRIVACY_POLICY -> {
118                 // Set the icon.
119                 dialogBuilder.setIcon(R.drawable.privacy_policy)
120
121                 // Set the title.
122                 dialogBuilder.setTitle(R.string.privacy_policy)
123             }
124
125             CHANGELOG -> {
126                 // Set the icon.
127                 dialogBuilder.setIcon(R.drawable.changelog)
128
129                 // Set the title.
130                 dialogBuilder.setTitle(R.string.changelog)
131             }
132
133             LICENSES -> {
134                 // Set the icon.
135                 dialogBuilder.setIcon(R.drawable.licenses)
136
137                 // Set the title.
138                 dialogBuilder.setTitle(R.string.licenses)
139             }
140
141             CONTRIBUTORS -> {
142                 // Set the icon.
143                 dialogBuilder.setIcon(R.drawable.contributors)
144
145                 // Set the tile.
146                 dialogBuilder.setTitle(R.string.contributors)
147             }
148
149             STINGRAY -> {
150                 // Set the icon.
151                 dialogBuilder.setIcon(R.drawable.secure_5g_nr_sa)
152
153                 // Set the tile.
154                 dialogBuilder.setTitle(R.string.stingrays)
155             }
156
157             NETWORK_UNKNOWN -> {
158                 // Set the icon.
159                 dialogBuilder.setIcon(R.drawable.privacy_policy)
160
161                 // Set the title.
162                 dialogBuilder.setTitle(R.string.unknown)
163             }
164
165             NETWORK_GPRS -> {
166                 // Set the icon.
167                 dialogBuilder.setIcon(R.drawable.privacy_policy)
168
169                 // Set the title.
170                 dialogBuilder.setTitle(R.string.gprs)
171             }
172
173             NETWORK_EDGE -> {
174                 // Set the icon.
175                 dialogBuilder.setIcon(R.drawable.privacy_policy)
176
177                 // Set the title.
178                 dialogBuilder.setTitle(R.string.edge)
179             }
180
181             NETWORK_UMTS -> {
182                 // Set the icon.
183                 dialogBuilder.setIcon(R.drawable.privacy_policy)
184
185                 // Set the title.
186                 dialogBuilder.setTitle(R.string.umts)
187             }
188
189             NETWORK_CDMA -> {
190                 // Set the icon.
191                 dialogBuilder.setIcon(R.drawable.privacy_policy)
192
193                 // Set the title.
194                 dialogBuilder.setTitle(R.string.cdma)
195             }
196
197             NETWORK_EVDO_0 -> {
198                 // Set the icon.
199                 dialogBuilder.setIcon(R.drawable.privacy_policy)
200
201                 // Set the title.
202                 dialogBuilder.setTitle(R.string.evdo_0)
203             }
204
205             NETWORK_EVDO_A -> {
206                 // Set the icon.
207                 dialogBuilder.setIcon(R.drawable.privacy_policy)
208
209                 // Set the title.
210                 dialogBuilder.setTitle(R.string.evdo_a)
211             }
212
213             NETWORK_1xRTT -> {
214                 // Set the icon.
215                 dialogBuilder.setIcon(R.drawable.privacy_policy)
216
217                 // Set the title.
218                 dialogBuilder.setTitle(R.string.rtt)
219             }
220
221             NETWORK_HSDPA -> {
222                 // Set the icon.
223                 dialogBuilder.setIcon(R.drawable.privacy_policy)
224
225                 // Set the title.
226                 dialogBuilder.setTitle(R.string.hsdpa)
227             }
228
229             NETWORK_HSUPA -> {
230                 // Set the icon.
231                 dialogBuilder.setIcon(R.drawable.privacy_policy)
232
233                 // Set the title.
234                 dialogBuilder.setTitle(R.string.hsupa)
235             }
236
237             NETWORK_HSPA -> {
238                 // Set the icon.
239                 dialogBuilder.setIcon(R.drawable.privacy_policy)
240
241                 // Set the title.
242                 dialogBuilder.setTitle(R.string.hspa)
243             }
244
245             NETWORK_IDEN -> {
246                 // Set the icon.
247                 dialogBuilder.setIcon(R.drawable.privacy_policy)
248
249                 // Set the title.
250                 dialogBuilder.setTitle(R.string.iden)
251             }
252
253             NETWORK_EVDO_B -> {
254                 // Set the icon.
255                 dialogBuilder.setIcon(R.drawable.privacy_policy)
256
257                 // Set the title.
258                 dialogBuilder.setTitle(R.string.evdo_b)
259             }
260
261             NETWORK_LTE -> {
262                 // Set the icon.
263                 dialogBuilder.setIcon(R.drawable.privacy_policy)
264
265                 // Set the title.
266                 dialogBuilder.setTitle(R.string.lte)
267             }
268
269             NETWORK_EHRPD -> {
270                 // Set the icon.
271                 dialogBuilder.setIcon(R.drawable.privacy_policy)
272
273                 // Set the title.
274                 dialogBuilder.setTitle(R.string.ehrpd)
275             }
276
277             NETWORK_HSPAP -> {
278                 // Set the icon.
279                 dialogBuilder.setIcon(R.drawable.privacy_policy)
280
281                 // Set the title.
282                 dialogBuilder.setTitle(R.string.hspap)
283             }
284
285             NETWORK_GSM -> {
286                 // Set the icon.
287                 dialogBuilder.setIcon(R.drawable.privacy_policy)
288
289                 // Set the title.
290                 dialogBuilder.setTitle(R.string.gsm)
291             }
292
293             NETWORK_TD_SCDMA -> {
294                 // Set the icon.
295                 dialogBuilder.setIcon(R.drawable.privacy_policy)
296
297                 // Set the title.
298                 dialogBuilder.setTitle(R.string.td_scdma)
299             }
300
301             NETWORK_IWLAN -> {
302                 // Set the icon.
303                 dialogBuilder.setIcon(R.drawable.privacy_policy)
304
305                 // Set the title.
306                 dialogBuilder.setTitle(R.string.iwlan)
307             }
308
309             NETWORK_NR -> {
310                 // Set the icon.
311                 dialogBuilder.setIcon(R.drawable.privacy_policy)
312
313                 // Set the title.
314                 dialogBuilder.setTitle(R.string.nr)
315             }
316
317             OVERRIDE_NETWORK_NONE -> {
318                 // Set the icon.
319                 dialogBuilder.setIcon(R.drawable.privacy_policy)
320
321                 // Set the title.
322                 dialogBuilder.setTitle(R.string.none)
323             }
324
325             OVERRIDE_NETWORK_LTE_CA -> {
326                 // Set the icon.
327                 dialogBuilder.setIcon(R.drawable.privacy_policy)
328
329                 // Set the title.
330                 dialogBuilder.setTitle(R.string.lte_ca)
331             }
332
333             OVERRIDE_NETWORK_LTE_ADVANCED_PRO -> {
334                 // Set the icon.
335                 dialogBuilder.setIcon(R.drawable.privacy_policy)
336
337                 // Set the title.
338                 dialogBuilder.setTitle(R.string.lte_ca)
339             }
340
341             OVERRIDE_NETWORK_NR_NSA -> {
342                 // Set the icon.
343                 dialogBuilder.setIcon(R.drawable.privacy_policy)
344
345                 // Set the title.
346                 dialogBuilder.setTitle(R.string.nr_nsa)
347             }
348
349             OVERRIDE_NETWORK_NR_NSA_MMWAVE -> {
350                 // Set the icon.
351                 dialogBuilder.setIcon(R.drawable.privacy_policy)
352
353                 // Set the title.
354                 dialogBuilder.setTitle(R.string.nr_nsa_mmwave)
355             }
356         }
357
358         // Set the view.
359         dialogBuilder.setView(R.layout.webview_dialog)
360
361         // Set a listener on the close button.  Using `null` as the listener closes the dialog without doing anything else.
362         dialogBuilder.setNegativeButton(R.string.close, null)
363
364         // Create an alert dialog from the builder.
365         val alertDialog = dialogBuilder.create()
366
367         // The alert dialog needs to be shown before the contents can be modified.
368         alertDialog.show()
369
370         // Get a handle for the WebView.
371         webView = alertDialog.findViewById(R.id.webview)!!
372
373         // Get the current theme status.
374         val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
375
376         // Check to see if the app is in night mode.
377         if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {  // The app is in night mode.
378             // Apply the dark WebView theme.
379             WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON)
380         }
381
382         // Create a WebView asset loader.
383         val webViewAssetLoader = WebViewAssetLoader.Builder().addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(requireContext())).build()
384
385         // Set a WebView client.
386         webView.webViewClient = object : WebViewClient() {
387             // Send external links to a web browser.
388             override fun shouldOverrideUrlLoading(view: WebView, webResourceRequest: WebResourceRequest): Boolean {
389                 // Create an intent to view the URL.
390                 val urlIntent = Intent(Intent.ACTION_VIEW)
391
392                 // Add the URL to the intent.
393                 urlIntent.data = webResourceRequest.url
394
395                 // Make it so.
396                 startActivity(urlIntent)
397
398                 // Consume the click.
399                 return true
400             }
401
402             // Process asset requests with the asset loader.
403             override fun shouldInterceptRequest(webView: WebView, webResourceRequest: WebResourceRequest): WebResourceResponse? {
404                 // This allows using the `appassets.androidplatform.net` URL, which handles the loading of SVG files, which otherwise is prevented by the CORS policy.
405                 return webViewAssetLoader.shouldInterceptRequest(webResourceRequest.url)
406             }
407         }
408
409         // Load the WebView data according to the dialog type.
410         when (dialogType) {
411             PERMISSIONS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/permissions.html")
412             PRIVACY_POLICY -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/privacy_policy.html")
413             CHANGELOG -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/changelog.html")
414             LICENSES -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/licenses.html")
415             CONTRIBUTORS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/contributors.html")
416             STINGRAY -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/stingrays.html")
417             NETWORK_UNKNOWN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_unknown.html")
418             NETWORK_GPRS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_gprs.html")
419             NETWORK_EDGE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_edge.html")
420             NETWORK_UMTS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_umts.html")
421             NETWORK_CDMA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_cdma.html")
422             NETWORK_EVDO_0 -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_0.html")
423             NETWORK_EVDO_A -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_a.html")
424             NETWORK_1xRTT -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_1xrtt.html")
425             NETWORK_HSDPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hsdpa.html")
426             NETWORK_HSUPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hsupa.html")
427             NETWORK_HSPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hspa.html")
428             NETWORK_IDEN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_iden.html")
429             NETWORK_EVDO_B -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_b.html")
430             NETWORK_LTE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_lte.html")
431             NETWORK_EHRPD -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_ehrpd.html")
432             NETWORK_HSPAP -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hspap.html")
433             NETWORK_GSM -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_gsm.html")
434             NETWORK_TD_SCDMA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_td_scdma.html")
435             NETWORK_IWLAN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_iwlan.html")
436             NETWORK_NR -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_nr.html")
437             OVERRIDE_NETWORK_NONE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_none.html")
438             OVERRIDE_NETWORK_LTE_CA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_lte_ca.html")
439             OVERRIDE_NETWORK_LTE_ADVANCED_PRO -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) +
440                     "/explanations/override_network_lte_advanced_pro.html")
441             OVERRIDE_NETWORK_NR_NSA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_nsa.html")
442             OVERRIDE_NETWORK_NR_NSA_MMWAVE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_nsa_mmwave.html")
443         }
444
445         // Scroll the WebView if the saved instance state is not null.
446         if (savedInstanceState != null) {
447             webView.post {
448                 webView.scrollY = savedInstanceState.getInt(SCROLL_Y)
449             }
450         }
451
452         // Return the alert dialog.
453         return alertDialog
454     }
455
456     override fun onSaveInstanceState(savedInstanceState: Bundle) {
457         // Run the default commands.
458         super.onSaveInstanceState(savedInstanceState)
459
460         // Save the scroll position.
461         savedInstanceState.putInt(SCROLL_Y, webView.scrollY)
462     }
463 }