2 * Copyright © 2021 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 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
79 // Define the class views.
80 private lateinit var webView: WebView
82 // Populate the WebView dialog type.
83 fun type(dialogType: Int): WebViewDialog {
84 // Create an arguments bundle.
85 val argumentsBundle = Bundle()
87 // Add the dialog type to the bundle.
88 argumentsBundle.putInt(DIALOG_TYPE, dialogType)
90 // Create a new instance of the WebView dialog.
91 val webViewDialog = WebViewDialog()
93 // Add the arguments bundle to the new dialog.
94 webViewDialog.arguments = argumentsBundle
96 // Return the new dialog.
100 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
101 // Get the dialog type from the arguments bundle.
102 val dialogType = requireArguments().getInt(DIALOG_TYPE)
104 // Use a builder to create the alert dialog.
105 val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.Theme_PrivacyCellAlertDialog)
107 // Set the icon and the title according to the dialog type.
111 dialogBuilder.setIcon(R.drawable.permissions)
114 dialogBuilder.setTitle(R.string.permissions)
119 dialogBuilder.setIcon(R.drawable.privacy_policy)
122 dialogBuilder.setTitle(R.string.privacy_policy)
127 dialogBuilder.setIcon(R.drawable.changelog)
130 dialogBuilder.setTitle(R.string.changelog)
135 dialogBuilder.setIcon(R.drawable.licenses)
138 dialogBuilder.setTitle(R.string.licenses)
143 dialogBuilder.setIcon(R.drawable.contributors)
146 dialogBuilder.setTitle(R.string.contributors)
151 dialogBuilder.setIcon(R.drawable.secure_5g_nr_sa)
154 dialogBuilder.setTitle(R.string.stingrays)
159 dialogBuilder.setIcon(R.drawable.privacy_policy)
162 dialogBuilder.setTitle(R.string.unknown)
167 dialogBuilder.setIcon(R.drawable.privacy_policy)
170 dialogBuilder.setTitle(R.string.gprs)
175 dialogBuilder.setIcon(R.drawable.privacy_policy)
178 dialogBuilder.setTitle(R.string.edge)
183 dialogBuilder.setIcon(R.drawable.privacy_policy)
186 dialogBuilder.setTitle(R.string.umts)
191 dialogBuilder.setIcon(R.drawable.privacy_policy)
194 dialogBuilder.setTitle(R.string.cdma)
199 dialogBuilder.setIcon(R.drawable.privacy_policy)
202 dialogBuilder.setTitle(R.string.evdo_0)
207 dialogBuilder.setIcon(R.drawable.privacy_policy)
210 dialogBuilder.setTitle(R.string.evdo_a)
215 dialogBuilder.setIcon(R.drawable.privacy_policy)
218 dialogBuilder.setTitle(R.string.rtt)
223 dialogBuilder.setIcon(R.drawable.privacy_policy)
226 dialogBuilder.setTitle(R.string.hsdpa)
231 dialogBuilder.setIcon(R.drawable.privacy_policy)
234 dialogBuilder.setTitle(R.string.hsupa)
239 dialogBuilder.setIcon(R.drawable.privacy_policy)
242 dialogBuilder.setTitle(R.string.hspa)
247 dialogBuilder.setIcon(R.drawable.privacy_policy)
250 dialogBuilder.setTitle(R.string.iden)
255 dialogBuilder.setIcon(R.drawable.privacy_policy)
258 dialogBuilder.setTitle(R.string.evdo_b)
263 dialogBuilder.setIcon(R.drawable.privacy_policy)
266 dialogBuilder.setTitle(R.string.lte)
271 dialogBuilder.setIcon(R.drawable.privacy_policy)
274 dialogBuilder.setTitle(R.string.ehrpd)
279 dialogBuilder.setIcon(R.drawable.privacy_policy)
282 dialogBuilder.setTitle(R.string.hspap)
287 dialogBuilder.setIcon(R.drawable.privacy_policy)
290 dialogBuilder.setTitle(R.string.gsm)
293 NETWORK_TD_SCDMA -> {
295 dialogBuilder.setIcon(R.drawable.privacy_policy)
298 dialogBuilder.setTitle(R.string.td_scdma)
303 dialogBuilder.setIcon(R.drawable.privacy_policy)
306 dialogBuilder.setTitle(R.string.iwlan)
311 dialogBuilder.setIcon(R.drawable.privacy_policy)
314 dialogBuilder.setTitle(R.string.nr)
317 OVERRIDE_NETWORK_NONE -> {
319 dialogBuilder.setIcon(R.drawable.privacy_policy)
322 dialogBuilder.setTitle(R.string.none)
325 OVERRIDE_NETWORK_LTE_CA -> {
327 dialogBuilder.setIcon(R.drawable.privacy_policy)
330 dialogBuilder.setTitle(R.string.lte_ca)
333 OVERRIDE_NETWORK_LTE_ADVANCED_PRO -> {
335 dialogBuilder.setIcon(R.drawable.privacy_policy)
338 dialogBuilder.setTitle(R.string.lte_ca)
341 OVERRIDE_NETWORK_NR_NSA -> {
343 dialogBuilder.setIcon(R.drawable.privacy_policy)
346 dialogBuilder.setTitle(R.string.nr_nsa)
349 OVERRIDE_NETWORK_NR_NSA_MMWAVE -> {
351 dialogBuilder.setIcon(R.drawable.privacy_policy)
354 dialogBuilder.setTitle(R.string.nr_nsa_mmwave)
359 dialogBuilder.setView(R.layout.webview_dialog)
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)
364 // Create an alert dialog from the builder.
365 val alertDialog = dialogBuilder.create()
367 // The alert dialog needs to be shown before the contents can be modified.
370 // Get a handle for the WebView.
371 webView = alertDialog.findViewById(R.id.webview)!!
373 // Get the current theme status.
374 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
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)
382 // Create a WebView asset loader.
383 val webViewAssetLoader = WebViewAssetLoader.Builder().addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(requireContext())).build()
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)
392 // Add the URL to the intent.
393 urlIntent.data = webResourceRequest.url
396 startActivity(urlIntent)
398 // Consume the click.
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)
409 // Load the WebView data according to the dialog type.
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")
445 // Scroll the WebView if the saved instance state is not null.
446 if (savedInstanceState != null) {
448 webView.scrollY = savedInstanceState.getInt(SCROLL_Y)
452 // Return the alert dialog.
456 override fun onSaveInstanceState(savedInstanceState: Bundle) {
457 // Run the default commands.
458 super.onSaveInstanceState(savedInstanceState)
460 // Save the scroll position.
461 savedInstanceState.putInt(SCROLL_Y, webView.scrollY)