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 Browser. 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
53 // Define the class views.
54 private lateinit var webView: WebView
56 // Populate the WebView dialog type.
57 fun type(dialogType: Int): WebViewDialog {
58 // Create an arguments bundle.
59 val argumentsBundle = Bundle()
61 // Add the dialog type to the bundle.
62 argumentsBundle.putInt(DIALOG_TYPE, dialogType)
64 // Create a new instance of the WebView dialog.
65 val webViewDialog = WebViewDialog()
67 // Add the arguments bundle to the new dialog.
68 webViewDialog.arguments = argumentsBundle
70 // Return the new dialog.
74 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
75 // Get the dialog type from the arguments bundle.
76 val dialogType = requireArguments().getInt(DIALOG_TYPE)
78 // Use a builder to create the alert dialog.
79 val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.Theme_PrivacyCellAlertDialog)
81 // Set the icon and the title according to the dialog type.
85 dialogBuilder.setIcon(R.drawable.permissions)
88 dialogBuilder.setTitle(R.string.permissions)
93 dialogBuilder.setIcon(R.drawable.privacy_policy)
96 dialogBuilder.setTitle(R.string.privacy_policy)
101 dialogBuilder.setIcon(R.drawable.changelog)
104 dialogBuilder.setTitle(R.string.changelog)
109 dialogBuilder.setIcon(R.drawable.licenses)
112 dialogBuilder.setTitle(R.string.licenses)
117 dialogBuilder.setIcon(R.drawable.contributors)
120 dialogBuilder.setTitle(R.string.contributors)
125 dialogBuilder.setView(R.layout.webview_dialog)
127 // Set a listener on the close button. Using `null` as the listener closes the dialog without doing anything else.
128 dialogBuilder.setNegativeButton(R.string.close, null)
130 // Create an alert dialog from the builder.
131 val alertDialog = dialogBuilder.create()
133 // The alert dialog needs to be shown before the contents can be modified.
136 // Get a handle for the WebView.
137 webView = alertDialog.findViewById(R.id.webview)!!
139 // Get the current theme status.
140 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
142 // Check to see if the app is in night mode.
143 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { // The app is in night mode.
144 // Apply the dark WebView theme.
145 WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON)
148 // Create a WebView asset loader.
149 val webViewAssetLoader = WebViewAssetLoader.Builder().addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(requireContext())).build()
151 // Set a WebView client.
152 webView.webViewClient = object : WebViewClient() {
153 // Send external links to a web browser.
154 override fun shouldOverrideUrlLoading(view: WebView, webResourceRequest: WebResourceRequest): Boolean {
155 // Create an intent to view the URL.
156 val urlIntent = Intent(Intent.ACTION_VIEW)
158 // Add the URL to the intent.
159 urlIntent.data = webResourceRequest.url
162 startActivity(urlIntent)
164 // Consume the click.
168 // Process asset requests with the asset loader.
169 override fun shouldInterceptRequest(webView: WebView, webResourceRequest: WebResourceRequest): WebResourceResponse? {
170 // This allows using the `appassets.androidplatform.net` URL, which handles the loading of SVG files, which otherwise is prevented by the CORS policy.
171 return webViewAssetLoader.shouldInterceptRequest(webResourceRequest.url)
175 // Load the WebView data according to the dialog type.
177 PERMISSIONS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/permissions.html")
178 PRIVACY_POLICY -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/privacy_policy.html")
179 CHANGELOG -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/changelog.html")
180 LICENSES -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/licenses.html")
181 CONTRIBUTORS -> webView.loadUrl("https://appassets.androidplatform.net/assets/" + getString(R.string.asset_directory) + "/contributors.html")
184 // Scroll the WebView if the saved instance state is not null.
185 if (savedInstanceState != null) {
187 webView.scrollY = savedInstanceState.getInt(SCROLL_Y)
191 // Return the alert dialog.
195 override fun onSaveInstanceState(savedInstanceState: Bundle) {
196 // Run the default commands.
197 super.onSaveInstanceState(savedInstanceState)
199 // Save the scroll position.
200 savedInstanceState.putInt(SCROLL_Y, webView.scrollY)