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.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
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
37 import com.stoutner.privacycell.R
39 // Define the class constants.
40 private const val DIALOG_TYPE = "dialog_type"
41 private const val SCROLL_Y = "scroll_y"
43 class WebViewDialog : DialogFragment() {
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 ANTIQUATED_NETWORK = 6
53 const val NETWORK_UNKNOWN = 7
54 const val NETWORK_GPRS = 8
55 const val NETWORK_EDGE = 9
56 const val NETWORK_UMTS = 10
57 const val NETWORK_CDMA = 11
58 const val NETWORK_EVDO_0 = 12
59 const val NETWORK_EVDO_A = 13
60 const val NETWORK_1xRTT = 14
61 const val NETWORK_HSDPA = 15
62 const val NETWORK_HSUPA = 16
63 const val NETWORK_HSPA = 17
64 const val NETWORK_IDEN = 18
65 const val NETWORK_EVDO_B = 19
66 const val NETWORK_LTE = 20
67 const val NETWORK_EHRPD = 21
68 const val NETWORK_HSPAP = 22
69 const val NETWORK_GSM = 23
70 const val NETWORK_TD_SCDMA = 24
71 const val NETWORK_IWLAN = 25
72 const val NETWORK_NR = 26
73 const val OVERRIDE_NETWORK_NONE = 27
74 const val OVERRIDE_NETWORK_LTE_CA = 28
75 const val OVERRIDE_NETWORK_LTE_ADVANCED_PRO = 29
76 const val OVERRIDE_NETWORK_NR_NSA = 30
77 const val OVERRIDE_NETWORK_NR_NSA_MMWAVE = 31 // Can be removed once the minimum API >= 31.
78 const val OVERRIDE_NETWORK_NR_ADVANCED = 32
81 // Define the class views.
82 private lateinit var webView: WebView
84 // Populate the WebView dialog type.
85 fun type(dialogType: Int): WebViewDialog {
86 // Create an arguments bundle.
87 val argumentsBundle = Bundle()
89 // Add the dialog type to the bundle.
90 argumentsBundle.putInt(DIALOG_TYPE, dialogType)
92 // Create a new instance of the WebView dialog.
93 val webViewDialog = WebViewDialog()
95 // Add the arguments bundle to the new dialog.
96 webViewDialog.arguments = argumentsBundle
98 // Return the new dialog.
102 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
103 // Get the dialog type from the arguments bundle.
104 val dialogType = requireArguments().getInt(DIALOG_TYPE)
106 // Use a builder to create the alert dialog.
107 val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.Theme_PrivacyCellAlertDialog)
109 // Set the icon and the title according to the dialog type.
113 dialogBuilder.setIcon(R.drawable.permissions)
116 dialogBuilder.setTitle(R.string.permissions)
121 dialogBuilder.setIcon(R.drawable.privacy_policy)
124 dialogBuilder.setTitle(R.string.privacy_policy)
129 dialogBuilder.setIcon(R.drawable.changelog)
132 dialogBuilder.setTitle(R.string.changelog)
137 dialogBuilder.setIcon(R.drawable.licenses)
140 dialogBuilder.setTitle(R.string.licenses)
145 dialogBuilder.setIcon(R.drawable.contributors)
148 dialogBuilder.setTitle(R.string.contributors)
153 dialogBuilder.setIcon(R.drawable.secure)
156 dialogBuilder.setTitle(R.string.stingrays)
159 ANTIQUATED_NETWORK -> {
161 dialogBuilder.setIcon(R.drawable.antiquated)
164 dialogBuilder.setTitle(R.string.antiquated_network_title)
169 dialogBuilder.setIcon(R.drawable.protocols)
172 dialogBuilder.setTitle(R.string.unknown)
177 dialogBuilder.setIcon(R.drawable.protocols)
180 dialogBuilder.setTitle(R.string.gprs)
185 dialogBuilder.setIcon(R.drawable.protocols)
188 dialogBuilder.setTitle(R.string.edge)
193 dialogBuilder.setIcon(R.drawable.protocols)
196 dialogBuilder.setTitle(R.string.umts)
201 dialogBuilder.setIcon(R.drawable.protocols)
204 dialogBuilder.setTitle(R.string.cdma)
209 dialogBuilder.setIcon(R.drawable.protocols)
212 dialogBuilder.setTitle(R.string.evdo_0)
217 dialogBuilder.setIcon(R.drawable.protocols)
220 dialogBuilder.setTitle(R.string.evdo_a)
225 dialogBuilder.setIcon(R.drawable.protocols)
228 dialogBuilder.setTitle(R.string.rtt)
233 dialogBuilder.setIcon(R.drawable.protocols)
236 dialogBuilder.setTitle(R.string.hsdpa)
241 dialogBuilder.setIcon(R.drawable.protocols)
244 dialogBuilder.setTitle(R.string.hsupa)
249 dialogBuilder.setIcon(R.drawable.protocols)
252 dialogBuilder.setTitle(R.string.hspa)
257 dialogBuilder.setIcon(R.drawable.protocols)
260 dialogBuilder.setTitle(R.string.iden)
265 dialogBuilder.setIcon(R.drawable.protocols)
268 dialogBuilder.setTitle(R.string.evdo_b)
273 dialogBuilder.setIcon(R.drawable.protocols)
276 dialogBuilder.setTitle(R.string.lte)
281 dialogBuilder.setIcon(R.drawable.protocols)
284 dialogBuilder.setTitle(R.string.ehrpd)
289 dialogBuilder.setIcon(R.drawable.protocols)
292 dialogBuilder.setTitle(R.string.hspap)
297 dialogBuilder.setIcon(R.drawable.protocols)
300 dialogBuilder.setTitle(R.string.gsm)
303 NETWORK_TD_SCDMA -> {
305 dialogBuilder.setIcon(R.drawable.protocols)
308 dialogBuilder.setTitle(R.string.td_scdma)
313 dialogBuilder.setIcon(R.drawable.protocols)
316 dialogBuilder.setTitle(R.string.iwlan)
321 dialogBuilder.setIcon(R.drawable.protocols)
324 dialogBuilder.setTitle(R.string.nr)
327 OVERRIDE_NETWORK_NONE -> {
329 dialogBuilder.setIcon(R.drawable.protocols)
332 dialogBuilder.setTitle(R.string.none)
335 OVERRIDE_NETWORK_LTE_CA -> {
337 dialogBuilder.setIcon(R.drawable.protocols)
340 dialogBuilder.setTitle(R.string.lte_ca)
343 OVERRIDE_NETWORK_LTE_ADVANCED_PRO -> {
345 dialogBuilder.setIcon(R.drawable.protocols)
348 dialogBuilder.setTitle(R.string.lte_advanced_pro)
351 OVERRIDE_NETWORK_NR_NSA -> {
353 dialogBuilder.setIcon(R.drawable.protocols)
356 dialogBuilder.setTitle(R.string.nr_nsa)
359 OVERRIDE_NETWORK_NR_NSA_MMWAVE -> {
361 dialogBuilder.setIcon(R.drawable.protocols)
364 dialogBuilder.setTitle(R.string.nr_nsa_mmwave)
367 OVERRIDE_NETWORK_NR_ADVANCED -> {
369 dialogBuilder.setIcon(R.drawable.protocols)
372 dialogBuilder.setTitle(R.string.nr_advanced)
377 dialogBuilder.setView(R.layout.webview_dialog)
379 // Set a listener on the close button. Using `null` as the listener closes the dialog without doing anything else.
380 dialogBuilder.setNegativeButton(R.string.close, null)
382 // Create an alert dialog from the builder.
383 val alertDialog = dialogBuilder.create()
385 // The alert dialog needs to be shown before the contents can be modified.
388 // Get a handle for the WebView.
389 webView = alertDialog.findViewById(R.id.webview)!!
391 // Get the current theme status.
392 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
394 // Check to see if the app is in night mode.
395 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // The app is in night mode.
396 // Apply the dark WebView theme.
397 WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON)
400 // Create a WebView asset loader.
401 val webViewAssetLoader = WebViewAssetLoader.Builder().addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(requireContext())).build()
403 // Set a WebView client.
404 webView.webViewClient = object : WebViewClient() {
405 // Send external links to a web browser.
406 override fun shouldOverrideUrlLoading(view: WebView, webResourceRequest: WebResourceRequest): Boolean {
407 // Create an intent to view the URL.
408 val urlIntent = Intent(Intent.ACTION_VIEW)
410 // Add the URL to the intent.
411 urlIntent.data = webResourceRequest.url
414 startActivity(urlIntent)
416 // Consume the click.
420 // Process asset requests with the asset loader.
421 override fun shouldInterceptRequest(webView: WebView, webResourceRequest: WebResourceRequest): WebResourceResponse? {
422 // This allows using the `appassets.androidplatform.net` URL, which handles the loading of SVG files, which otherwise is prevented by the CORS policy.
423 return webViewAssetLoader.shouldInterceptRequest(webResourceRequest.url)
427 // Load the WebView data according to the dialog type.
429 PERMISSIONS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/permissions.html")
430 PRIVACY_POLICY -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/privacy_policy.html")
431 CHANGELOG -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/changelog.html")
432 LICENSES -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/licenses.html")
433 CONTRIBUTORS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/contributors.html")
434 STINGRAY -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/stingrays.html")
435 ANTIQUATED_NETWORK -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/antiquated_network.html")
436 NETWORK_UNKNOWN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_unknown.html")
437 NETWORK_GPRS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_gprs.html")
438 NETWORK_EDGE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_edge.html")
439 NETWORK_UMTS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_umts.html")
440 NETWORK_CDMA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_cdma.html")
441 NETWORK_EVDO_0 -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_0.html")
442 NETWORK_EVDO_A -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_a.html")
443 NETWORK_1xRTT -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_1xrtt.html")
444 NETWORK_HSDPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hsdpa.html")
445 NETWORK_HSUPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hsupa.html")
446 NETWORK_HSPA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hspa.html")
447 NETWORK_IDEN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_iden.html")
448 NETWORK_EVDO_B -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_evdo_b.html")
449 NETWORK_LTE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_lte.html")
450 NETWORK_EHRPD -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_ehrpd.html")
451 NETWORK_HSPAP -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_hspap.html")
452 NETWORK_GSM -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_gsm.html")
453 NETWORK_TD_SCDMA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_td_scdma.html")
454 NETWORK_IWLAN -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_iwlan.html")
455 NETWORK_NR -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/network_nr.html")
456 OVERRIDE_NETWORK_NONE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_none.html")
457 OVERRIDE_NETWORK_LTE_CA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_lte_ca.html")
458 OVERRIDE_NETWORK_LTE_ADVANCED_PRO -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) +
459 "/explanations/override_network_lte_advanced_pro.html")
460 OVERRIDE_NETWORK_NR_NSA -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_nsa.html")
461 // The item below can be removed once the minimum API >= 31.
462 OVERRIDE_NETWORK_NR_NSA_MMWAVE -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_nsa_mmwave.html")
463 OVERRIDE_NETWORK_NR_ADVANCED -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/explanations/override_network_nr_advanced.html")
466 // Scroll the WebView if the saved instance state is not null.
467 if (savedInstanceState != null) {
469 webView.scrollY = savedInstanceState.getInt(SCROLL_Y)
473 // Return the alert dialog.
477 override fun onSaveInstanceState(savedInstanceState: Bundle) {
478 // Run the default commands.
479 super.onSaveInstanceState(savedInstanceState)
481 // Save the scroll position.
482 savedInstanceState.putInt(SCROLL_Y, webView.scrollY)