2 * Copyright © 2018-2021 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
6 * Privacy Browser 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 Browser 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.privacybrowser.dialogs
22 import android.annotation.SuppressLint
23 import android.app.Dialog
24 import android.content.Context
25 import android.content.DialogInterface
26 import android.content.res.Configuration
27 import android.os.Bundle
28 import android.view.View
29 import android.view.WindowManager
30 import android.widget.TextView
32 import androidx.appcompat.app.AlertDialog
33 import androidx.fragment.app.DialogFragment
34 import androidx.preference.PreferenceManager
36 import com.stoutner.privacybrowser.R
37 import com.stoutner.privacybrowser.helpers.BlocklistHelper
39 // Define the class constants.
40 private const val ID = "id"
41 private const val IS_LAST_REQUEST = "is_last_request"
42 private const val REQUEST_DETAILS = "request_details"
44 class ViewRequestDialog : DialogFragment() {
45 // Define the class variables.
46 private lateinit var viewRequestListener: ViewRequestListener
48 // The public interface is used to send information back to the parent activity.
49 interface ViewRequestListener {
50 // Show the previous request.
51 fun onPrevious(currentId: Int)
53 // Show the next request.
54 fun onNext(currentId: Int)
57 override fun onAttach(context: Context) {
58 // Run the default commands.
59 super.onAttach(context)
61 // Get a handle for the listener from the launching context.
62 viewRequestListener = context as ViewRequestListener
66 // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin.
68 fun request(id: Int, isLastRequest: Boolean, requestDetails: Array<String>): ViewRequestDialog {
72 // Store the request details.
74 bundle.putBoolean(IS_LAST_REQUEST, isLastRequest)
75 bundle.putStringArray(REQUEST_DETAILS, requestDetails)
77 // Create a new instance of the view request dialog.
78 val viewRequestDialog = ViewRequestDialog()
80 // Add the arguments to the new dialog.
81 viewRequestDialog.arguments = bundle
83 // Return the new dialog.
84 return viewRequestDialog
88 // `@SuppressLint("InflateParams")` removes the warning about using null as the parent view group when inflating the alert dialog.
89 @SuppressLint("InflateParams")
90 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
91 // Get the arguments from the bundle.
92 val id = requireArguments().getInt(ID)
93 val isLastRequest = requireArguments().getBoolean(IS_LAST_REQUEST)
94 val requestDetails = requireArguments().getStringArray(REQUEST_DETAILS)!!
96 // Use an alert dialog builder to create the alert dialog.
97 val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
99 // Get the current theme status.
100 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
102 // Set the icon according to the theme.
103 dialogBuilder.setIconAttribute(R.attr.blockAdsBlueIcon)
106 dialogBuilder.setTitle(resources.getString(R.string.request_details) + " - " + id)
108 // Set the view. The parent view is null because it will be assigned by the alert dialog.
109 dialogBuilder.setView(layoutInflater.inflate(R.layout.view_request_dialog, null))
111 // Set the close button. Using `null` as the listener closes the dialog without doing anything else.
112 dialogBuilder.setNeutralButton(R.string.close, null)
114 // Set the previous button.
115 dialogBuilder.setNegativeButton(R.string.previous) { _: DialogInterface?, _: Int ->
116 // Load the previous request.
117 viewRequestListener.onPrevious(id)
120 // Set the next button.
121 dialogBuilder.setPositiveButton(R.string.next) { _: DialogInterface?, _: Int ->
122 // Load the next request.
123 viewRequestListener.onNext(id)
126 // Create an alert dialog from the alert dialog builder.
127 val alertDialog = dialogBuilder.create()
129 // Get a handle for the shared preferences.
130 val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
132 // Get the screenshot preference.
133 val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
135 // Disable screenshots if not allowed.
136 if (!allowScreenshots) {
137 // Disable screenshots.
138 alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
141 //The alert dialog must be shown before the contents can be modified.
144 // Get handles for the dialog views.
145 val requestDisposition = alertDialog.findViewById<TextView>(R.id.request_disposition)!!
146 val requestUrl = alertDialog.findViewById<TextView>(R.id.request_url)!!
147 val requestBlockListLabel = alertDialog.findViewById<TextView>(R.id.request_blocklist_label)!!
148 val requestBlockList = alertDialog.findViewById<TextView>(R.id.request_blocklist)!!
149 val requestSubListLabel = alertDialog.findViewById<TextView>(R.id.request_sublist_label)!!
150 val requestSubList = alertDialog.findViewById<TextView>(R.id.request_sublist)!!
151 val requestBlockListEntriesLabel = alertDialog.findViewById<TextView>(R.id.request_blocklist_entries_label)!!
152 val requestBlockListEntries = alertDialog.findViewById<TextView>(R.id.request_blocklist_entries)!!
153 val requestBlockListOriginalEntryLabel = alertDialog.findViewById<TextView>(R.id.request_blocklist_original_entry_label)!!
154 val requestBlockListOriginalEntry = alertDialog.findViewById<TextView>(R.id.request_blocklist_original_entry)!!
155 val previousButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE)
156 val nextButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE)
158 // Disable the previous button if the first resource request is displayed.
159 previousButton.isEnabled = (id != 1)
161 // Disable the next button if the last resource request is displayed.
162 nextButton.isEnabled = !isLastRequest
164 // Set the request action text.
165 when (requestDetails[BlocklistHelper.REQUEST_DISPOSITION]) {
166 BlocklistHelper.REQUEST_DEFAULT -> {
168 requestDisposition.setText(R.string.default_allowed)
170 // Set the background color. The deprecated `getColor()` must be used until the minimum API >= 23.
171 @Suppress("DEPRECATION")
172 requestDisposition.setBackgroundColor(resources.getColor(R.color.transparent))
175 BlocklistHelper.REQUEST_ALLOWED -> {
177 requestDisposition.setText(R.string.allowed)
179 // Set the background color according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
180 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
181 @Suppress("DEPRECATION")
182 requestDisposition.setBackgroundColor(resources.getColor(R.color.blue_100))
184 @Suppress("DEPRECATION")
185 requestDisposition.setBackgroundColor(resources.getColor(R.color.blue_700_50))
189 BlocklistHelper.REQUEST_THIRD_PARTY -> {
191 requestDisposition.setText(R.string.third_party_blocked)
193 // Set the background color according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
194 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
195 @Suppress("DEPRECATION")
196 requestDisposition.setBackgroundColor(resources.getColor(R.color.yellow_100))
198 @Suppress("DEPRECATION")
199 requestDisposition.setBackgroundColor(resources.getColor(R.color.yellow_700_50))
202 BlocklistHelper.REQUEST_BLOCKED -> {
204 requestDisposition.setText(R.string.blocked)
206 // Set the background color according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
207 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
208 @Suppress("DEPRECATION")
209 requestDisposition.setBackgroundColor(resources.getColor(R.color.red_100))
211 @Suppress("DEPRECATION")
212 requestDisposition.setBackgroundColor(resources.getColor(R.color.red_700_40))
217 // Display the request URL.
218 requestUrl.text = requestDetails[BlocklistHelper.REQUEST_URL]
220 // Modify the dialog based on the request action.
221 if (requestDetails.size == 2) { // A default request.
222 // Hide the unused views.
223 requestBlockListLabel.visibility = View.GONE
224 requestBlockList.visibility = View.GONE
225 requestSubListLabel.visibility = View.GONE
226 requestSubList.visibility = View.GONE
227 requestBlockListEntriesLabel.visibility = View.GONE
228 requestBlockListEntries.visibility = View.GONE
229 requestBlockListOriginalEntryLabel.visibility = View.GONE
230 requestBlockListOriginalEntry.visibility = View.GONE
231 } else { // A blocked or allowed request.
232 // Set the text on the text views.
233 requestBlockList.text = requestDetails[BlocklistHelper.REQUEST_BLOCKLIST]
234 requestBlockListEntries.text = requestDetails[BlocklistHelper.REQUEST_BLOCKLIST_ENTRIES]
235 requestBlockListOriginalEntry.text = requestDetails[BlocklistHelper.REQUEST_BLOCKLIST_ORIGINAL_ENTRY]
236 when (requestDetails[BlocklistHelper.REQUEST_SUBLIST]) {
237 BlocklistHelper.MAIN_WHITELIST -> requestSubList.setText(R.string.main_whitelist)
238 BlocklistHelper.FINAL_WHITELIST -> requestSubList.setText(R.string.final_whitelist)
239 BlocklistHelper.DOMAIN_WHITELIST -> requestSubList.setText(R.string.domain_whitelist)
240 BlocklistHelper.DOMAIN_INITIAL_WHITELIST -> requestSubList.setText(R.string.domain_initial_whitelist)
241 BlocklistHelper.DOMAIN_FINAL_WHITELIST -> requestSubList.setText(R.string.domain_final_whitelist)
242 BlocklistHelper.THIRD_PARTY_WHITELIST -> requestSubList.setText(R.string.third_party_whitelist)
243 BlocklistHelper.THIRD_PARTY_DOMAIN_WHITELIST -> requestSubList.setText(R.string.third_party_domain_whitelist)
244 BlocklistHelper.THIRD_PARTY_DOMAIN_INITIAL_WHITELIST -> requestSubList.setText(R.string.third_party_domain_initial_whitelist)
245 BlocklistHelper.MAIN_BLACKLIST -> requestSubList.setText(R.string.main_blacklist)
246 BlocklistHelper.INITIAL_BLACKLIST -> requestSubList.setText(R.string.initial_blacklist)
247 BlocklistHelper.FINAL_BLACKLIST -> requestSubList.setText(R.string.final_blacklist)
248 BlocklistHelper.DOMAIN_BLACKLIST -> requestSubList.setText(R.string.domain_blacklist)
249 BlocklistHelper.DOMAIN_INITIAL_BLACKLIST -> requestSubList.setText(R.string.domain_initial_blacklist)
250 BlocklistHelper.DOMAIN_FINAL_BLACKLIST -> requestSubList.setText(R.string.domain_final_blacklist)
251 BlocklistHelper.DOMAIN_REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.domain_regular_expression_blacklist)
252 BlocklistHelper.THIRD_PARTY_BLACKLIST -> requestSubList.setText(R.string.third_party_blacklist)
253 BlocklistHelper.THIRD_PARTY_INITIAL_BLACKLIST -> requestSubList.setText(R.string.third_party_initial_blacklist)
254 BlocklistHelper.THIRD_PARTY_DOMAIN_BLACKLIST -> requestSubList.setText(R.string.third_party_domain_blacklist)
255 BlocklistHelper.THIRD_PARTY_DOMAIN_INITIAL_BLACKLIST -> requestSubList.setText(R.string.third_party_domain_initial_blacklist)
256 BlocklistHelper.THIRD_PARTY_REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.third_party_regular_expression_blacklist)
257 BlocklistHelper.THIRD_PARTY_DOMAIN_REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.third_party_domain_regular_expression_blacklist)
258 BlocklistHelper.REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.regular_expression_blacklist)
262 // Return the alert dialog.