2 * Copyright 2021-2022 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>.
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.
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.
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/>.
20 package com.stoutner.privacycell.dialogs
22 import android.app.Dialog
23 import android.content.Intent
24 import android.os.Bundle
25 import android.webkit.WebResourceRequest
26 import android.webkit.WebResourceResponse
27 import android.webkit.WebView
28 import android.webkit.WebViewClient
30 import androidx.appcompat.app.AlertDialog
31 import androidx.fragment.app.DialogFragment
32 import androidx.webkit.WebViewAssetLoader
34 import com.stoutner.privacycell.R
36 // Define the class constants.
37 private const val DIALOG_TYPE = "dialog_type"
38 private const val SCROLL_Y = "scroll_y"
40 class WebViewDialog : DialogFragment() {
42 // Define the public constants.
43 const val PERMISSIONS = 0
44 const val PRIVACY_POLICY = 1
45 const val CHANGELOG = 2
46 const val LICENSES = 3
47 const val CONTRIBUTORS = 4
48 const val STINGRAY = 5
49 const val ANTIQUATED_NETWORK = 6
50 const val NETWORK_UNKNOWN = 7
51 const val NETWORK_GPRS = 8
52 const val NETWORK_EDGE = 9
53 const val NETWORK_UMTS = 10
54 const val NETWORK_CDMA = 11
55 const val NETWORK_EVDO_0 = 12
56 const val NETWORK_EVDO_A = 13
57 const val NETWORK_1xRTT = 14
58 const val NETWORK_HSDPA = 15
59 const val NETWORK_HSUPA = 16
60 const val NETWORK_HSPA = 17
61 const val NETWORK_IDEN = 18
62 const val NETWORK_EVDO_B = 19
63 const val NETWORK_LTE = 20
64 const val NETWORK_EHRPD = 21
65 const val NETWORK_HSPAP = 22
66 const val NETWORK_GSM = 23
67 const val NETWORK_TD_SCDMA = 24
68 const val NETWORK_IWLAN = 25
69 const val NETWORK_NR = 26
70 const val OVERRIDE_NETWORK_NONE = 27
71 const val OVERRIDE_NETWORK_LTE_CA = 28
72 const val OVERRIDE_NETWORK_LTE_ADVANCED_PRO = 29
73 const val OVERRIDE_NETWORK_NR_NSA = 30
74 const val OVERRIDE_NETWORK_NR_NSA_MMWAVE = 31 // Can be removed once the minimum API >= 31.
75 const val OVERRIDE_NETWORK_NR_ADVANCED = 32
78 // Define the class views.
79 private lateinit var webView: WebView
81 // Populate the WebView dialog type.
82 fun type(dialogType: Int): WebViewDialog {
83 // Create an arguments bundle.
84 val argumentsBundle = Bundle()
86 // Add the dialog type to the bundle.
87 argumentsBundle.putInt(DIALOG_TYPE, dialogType)
89 // Create a new instance of the WebView dialog.
90 val webViewDialog = WebViewDialog()
92 // Add the arguments bundle to the new dialog.
93 webViewDialog.arguments = argumentsBundle
95 // Return the new dialog.
99 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
100 // Get the dialog type from the arguments bundle.
101 val dialogType = requireArguments().getInt(DIALOG_TYPE)
103 // Use a builder to create the alert dialog.
104 val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.Theme_PrivacyCellAlertDialog)
106 // Set the icon and the title according to the dialog type.
110 dialogBuilder.setIcon(R.drawable.permissions)
113 dialogBuilder.setTitle(R.string.permissions)
118 dialogBuilder.setIcon(R.drawable.privacy_policy)
121 dialogBuilder.setTitle(R.string.privacy_policy)
126 dialogBuilder.setIcon(R.drawable.changelog)
129 dialogBuilder.setTitle(R.string.changelog)
134 dialogBuilder.setIcon(R.drawable.licenses)
137 dialogBuilder.setTitle(R.string.licenses)
142 dialogBuilder.setIcon(R.drawable.contributors)
145 dialogBuilder.setTitle(R.string.contributors)
150 dialogBuilder.setIcon(R.drawable.secure)
153 dialogBuilder.setTitle(R.string.stingrays)
156 ANTIQUATED_NETWORK -> {
158 dialogBuilder.setIcon(R.drawable.antiquated)
161 dialogBuilder.setTitle(R.string.antiquated_network_title)
166 dialogBuilder.setIcon(R.drawable.protocols)
169 dialogBuilder.setTitle(R.string.unknown)
174 dialogBuilder.setIcon(R.drawable.protocols)
177 dialogBuilder.setTitle(R.string.gprs)
182 dialogBuilder.setIcon(R.drawable.protocols)
185 dialogBuilder.setTitle(R.string.edge)
190 dialogBuilder.setIcon(R.drawable.protocols)
193 dialogBuilder.setTitle(R.string.umts)
198 dialogBuilder.setIcon(R.drawable.protocols)
201 dialogBuilder.setTitle(R.string.cdma)
206 dialogBuilder.setIcon(R.drawable.protocols)
209 dialogBuilder.setTitle(R.string.evdo_0)
214 dialogBuilder.setIcon(R.drawable.protocols)
217 dialogBuilder.setTitle(R.string.evdo_a)
222 dialogBuilder.setIcon(R.drawable.protocols)
225 dialogBuilder.setTitle(R.string.rtt)
230 dialogBuilder.setIcon(R.drawable.protocols)
233 dialogBuilder.setTitle(R.string.hsdpa)
238 dialogBuilder.setIcon(R.drawable.protocols)
241 dialogBuilder.setTitle(R.string.hsupa)
246 dialogBuilder.setIcon(R.drawable.protocols)
249 dialogBuilder.setTitle(R.string.hspa)
254 dialogBuilder.setIcon(R.drawable.protocols)
257 dialogBuilder.setTitle(R.string.iden)
262 dialogBuilder.setIcon(R.drawable.protocols)
265 dialogBuilder.setTitle(R.string.evdo_b)
270 dialogBuilder.setIcon(R.drawable.protocols)
273 dialogBuilder.setTitle(R.string.lte)
278 dialogBuilder.setIcon(R.drawable.protocols)
281 dialogBuilder.setTitle(R.string.ehrpd)
286 dialogBuilder.setIcon(R.drawable.protocols)
289 dialogBuilder.setTitle(R.string.hspap)
294 dialogBuilder.setIcon(R.drawable.protocols)
297 dialogBuilder.setTitle(R.string.gsm)
300 NETWORK_TD_SCDMA -> {
302 dialogBuilder.setIcon(R.drawable.protocols)
305 dialogBuilder.setTitle(R.string.td_scdma)
310 dialogBuilder.setIcon(R.drawable.protocols)
313 dialogBuilder.setTitle(R.string.iwlan)
318 dialogBuilder.setIcon(R.drawable.protocols)
321 dialogBuilder.setTitle(R.string.nr)
324 OVERRIDE_NETWORK_NONE -> {
326 dialogBuilder.setIcon(R.drawable.protocols)
329 dialogBuilder.setTitle(R.string.none)
332 OVERRIDE_NETWORK_LTE_CA -> {
334 dialogBuilder.setIcon(R.drawable.protocols)
337 dialogBuilder.setTitle(R.string.lte_ca)
340 OVERRIDE_NETWORK_LTE_ADVANCED_PRO -> {
342 dialogBuilder.setIcon(R.drawable.protocols)
345 dialogBuilder.setTitle(R.string.lte_advanced_pro)
348 OVERRIDE_NETWORK_NR_NSA -> {
350 dialogBuilder.setIcon(R.drawable.protocols)
353 dialogBuilder.setTitle(R.string.nr_nsa)
356 OVERRIDE_NETWORK_NR_NSA_MMWAVE -> {
358 dialogBuilder.setIcon(R.drawable.protocols)
361 dialogBuilder.setTitle(R.string.nr_nsa_mmwave)
364 OVERRIDE_NETWORK_NR_ADVANCED -> {
366 dialogBuilder.setIcon(R.drawable.protocols)
369 dialogBuilder.setTitle(R.string.nr_advanced)
374 dialogBuilder.setView(R.layout.webview_dialog)
376 // Set a listener on the close button. Using `null` as the listener closes the dialog without doing anything else.
377 dialogBuilder.setNegativeButton(R.string.close, null)
379 // Create an alert dialog from the builder.
380 val alertDialog = dialogBuilder.create()
382 // The alert dialog needs to be shown before the contents can be modified.
385 // Get a handle for the WebView.
386 webView = alertDialog.findViewById(R.id.webview)!!
388 // Create a WebView asset loader.
389 val webViewAssetLoader = WebViewAssetLoader.Builder().addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(requireContext())).build()
391 // Set a WebView client.
392 webView.webViewClient = object : WebViewClient() {
393 // Send external links to a web browser.
394 override fun shouldOverrideUrlLoading(view: WebView, webResourceRequest: WebResourceRequest): Boolean {
395 // Create an intent to view the URL.
396 val urlIntent = Intent(Intent.ACTION_VIEW)
398 // Add the URL to the intent.
399 urlIntent.data = webResourceRequest.url
402 startActivity(urlIntent)
404 // Consume the click.
408 // Process asset requests with the asset loader.
409 override fun shouldInterceptRequest(webView: WebView, webResourceRequest: WebResourceRequest): WebResourceResponse? {
410 // This allows using the `appassets.androidplatform.net` URL, which handles the loading of SVG files, which otherwise is prevented by the CORS policy.
411 return webViewAssetLoader.shouldInterceptRequest(webResourceRequest.url)
415 // Load the WebView data according to the dialog type.
417 PERMISSIONS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/permissions.html")
418 PRIVACY_POLICY -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/privacy_policy.html")
419 CHANGELOG -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/changelog.html")
420 LICENSES -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/licenses.html")
421 CONTRIBUTORS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/contributors.html")
422 STINGRAY -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/stingrays.html")
423 ANTIQUATED_NETWORK -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/antiquated_network.html")
424 NETWORK_UNKNOWN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_unknown.html")
425 NETWORK_GPRS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_gprs.html")
426 NETWORK_EDGE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_edge.html")
427 NETWORK_UMTS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_umts.html")
428 NETWORK_CDMA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_cdma.html")
429 NETWORK_EVDO_0 -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_0.html")
430 NETWORK_EVDO_A -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_a.html")
431 NETWORK_1xRTT -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_1xrtt.html")
432 NETWORK_HSDPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hsdpa.html")
433 NETWORK_HSUPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hsupa.html")
434 NETWORK_HSPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hspa.html")
435 NETWORK_IDEN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_iden.html")
436 NETWORK_EVDO_B -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_b.html")
437 NETWORK_LTE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_lte.html")
438 NETWORK_EHRPD -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_ehrpd.html")
439 NETWORK_HSPAP -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hspap.html")
440 NETWORK_GSM -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_gsm.html")
441 NETWORK_TD_SCDMA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_td_scdma.html")
442 NETWORK_IWLAN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_iwlan.html")
443 NETWORK_NR -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_nr.html")
444 OVERRIDE_NETWORK_NONE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_none.html")
445 OVERRIDE_NETWORK_LTE_CA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_lte_ca.html")
446 OVERRIDE_NETWORK_LTE_ADVANCED_PRO -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) +
447 "/explanations/override_network_lte_advanced_pro.html")
448 OVERRIDE_NETWORK_NR_NSA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_nsa.html")
449 // The item below can be removed once the minimum API >= 31.
450 OVERRIDE_NETWORK_NR_NSA_MMWAVE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_nsa_mmwave.html")
451 OVERRIDE_NETWORK_NR_ADVANCED -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_advanced.html")
454 // Scroll the WebView if the saved instance state is not null.
455 if (savedInstanceState != null) {
457 webView.scrollY = savedInstanceState.getInt(SCROLL_Y)
461 // Return the alert dialog.
465 override fun onSaveInstanceState(savedInstanceState: Bundle) {
466 // Run the default commands.
467 super.onSaveInstanceState(savedInstanceState)
469 // Save the scroll position.
470 savedInstanceState.putInt(SCROLL_Y, webView.scrollY)