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 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
104 dialogBuilder.setIcon(R.drawable.block_ads_enabled_day)
106 dialogBuilder.setIcon(R.drawable.block_ads_enabled_night)
110 dialogBuilder.setTitle(resources.getString(R.string.request_details) + " - " + id)
112 // Set the view. The parent view is null because it will be assigned by the alert dialog.
113 dialogBuilder.setView(layoutInflater.inflate(R.layout.view_request_dialog, null))
115 // Set the close button. Using `null` as the listener closes the dialog without doing anything else.
116 dialogBuilder.setNeutralButton(R.string.close, null)
118 // Set the previous button.
119 dialogBuilder.setNegativeButton(R.string.previous) { _: DialogInterface?, _: Int ->
120 // Load the previous request.
121 viewRequestListener.onPrevious(id)
124 // Set the next button.
125 dialogBuilder.setPositiveButton(R.string.next) { _: DialogInterface?, _: Int ->
126 // Load the next request.
127 viewRequestListener.onNext(id)
130 // Create an alert dialog from the alert dialog builder.
131 val alertDialog = dialogBuilder.create()
133 // Get a handle for the shared preferences.
134 val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
136 // Get the screenshot preference.
137 val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
139 // Disable screenshots if not allowed.
140 if (!allowScreenshots) {
141 // Disable screenshots.
142 alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
145 //The alert dialog must be shown before the contents can be modified.
148 // Get handles for the dialog views.
149 val requestDisposition = alertDialog.findViewById<TextView>(R.id.request_disposition)!!
150 val requestUrl = alertDialog.findViewById<TextView>(R.id.request_url)!!
151 val requestBlockListLabel = alertDialog.findViewById<TextView>(R.id.request_blocklist_label)!!
152 val requestBlockList = alertDialog.findViewById<TextView>(R.id.request_blocklist)!!
153 val requestSubListLabel = alertDialog.findViewById<TextView>(R.id.request_sublist_label)!!
154 val requestSubList = alertDialog.findViewById<TextView>(R.id.request_sublist)!!
155 val requestBlockListEntriesLabel = alertDialog.findViewById<TextView>(R.id.request_blocklist_entries_label)!!
156 val requestBlockListEntries = alertDialog.findViewById<TextView>(R.id.request_blocklist_entries)!!
157 val requestBlockListOriginalEntryLabel = alertDialog.findViewById<TextView>(R.id.request_blocklist_original_entry_label)!!
158 val requestBlockListOriginalEntry = alertDialog.findViewById<TextView>(R.id.request_blocklist_original_entry)!!
159 val previousButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE)
160 val nextButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE)
162 // Disable the previous button if the first resource request is displayed.
163 previousButton.isEnabled = (id != 1)
165 // Disable the next button if the last resource request is displayed.
166 nextButton.isEnabled = !isLastRequest
168 // Set the request action text.
169 when (requestDetails[BlocklistHelper.REQUEST_DISPOSITION]) {
170 BlocklistHelper.REQUEST_DEFAULT -> {
172 requestDisposition.setText(R.string.default_allowed)
174 // Set the background color. The deprecated `getColor()` must be used until the minimum API >= 23.
175 @Suppress("DEPRECATION")
176 requestDisposition.setBackgroundColor(resources.getColor(R.color.transparent))
179 BlocklistHelper.REQUEST_ALLOWED -> {
181 requestDisposition.setText(R.string.allowed)
183 // Set the background color according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
184 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
185 @Suppress("DEPRECATION")
186 requestDisposition.setBackgroundColor(resources.getColor(R.color.blue_100))
188 @Suppress("DEPRECATION")
189 requestDisposition.setBackgroundColor(resources.getColor(R.color.blue_700_50))
193 BlocklistHelper.REQUEST_THIRD_PARTY -> {
195 requestDisposition.setText(R.string.third_party_blocked)
197 // Set the background color according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
198 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
199 @Suppress("DEPRECATION")
200 requestDisposition.setBackgroundColor(resources.getColor(R.color.yellow_100))
202 @Suppress("DEPRECATION")
203 requestDisposition.setBackgroundColor(resources.getColor(R.color.yellow_700_50))
206 BlocklistHelper.REQUEST_BLOCKED -> {
208 requestDisposition.setText(R.string.blocked)
210 // Set the background color according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
211 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
212 @Suppress("DEPRECATION")
213 requestDisposition.setBackgroundColor(resources.getColor(R.color.red_100))
215 @Suppress("DEPRECATION")
216 requestDisposition.setBackgroundColor(resources.getColor(R.color.red_700_40))
221 // Display the request URL.
222 requestUrl.text = requestDetails[BlocklistHelper.REQUEST_URL]
224 // Modify the dialog based on the request action.
225 if (requestDetails.size == 2) { // A default request.
226 // Hide the unused views.
227 requestBlockListLabel.visibility = View.GONE
228 requestBlockList.visibility = View.GONE
229 requestSubListLabel.visibility = View.GONE
230 requestSubList.visibility = View.GONE
231 requestBlockListEntriesLabel.visibility = View.GONE
232 requestBlockListEntries.visibility = View.GONE
233 requestBlockListOriginalEntryLabel.visibility = View.GONE
234 requestBlockListOriginalEntry.visibility = View.GONE
235 } else { // A blocked or allowed request.
236 // Set the text on the text views.
237 requestBlockList.text = requestDetails[BlocklistHelper.REQUEST_BLOCKLIST]
238 requestBlockListEntries.text = requestDetails[BlocklistHelper.REQUEST_BLOCKLIST_ENTRIES]
239 requestBlockListOriginalEntry.text = requestDetails[BlocklistHelper.REQUEST_BLOCKLIST_ORIGINAL_ENTRY]
240 when (requestDetails[BlocklistHelper.REQUEST_SUBLIST]) {
241 BlocklistHelper.MAIN_WHITELIST -> requestSubList.setText(R.string.main_whitelist)
242 BlocklistHelper.FINAL_WHITELIST -> requestSubList.setText(R.string.final_whitelist)
243 BlocklistHelper.DOMAIN_WHITELIST -> requestSubList.setText(R.string.domain_whitelist)
244 BlocklistHelper.DOMAIN_INITIAL_WHITELIST -> requestSubList.setText(R.string.domain_initial_whitelist)
245 BlocklistHelper.DOMAIN_FINAL_WHITELIST -> requestSubList.setText(R.string.domain_final_whitelist)
246 BlocklistHelper.THIRD_PARTY_WHITELIST -> requestSubList.setText(R.string.third_party_whitelist)
247 BlocklistHelper.THIRD_PARTY_DOMAIN_WHITELIST -> requestSubList.setText(R.string.third_party_domain_whitelist)
248 BlocklistHelper.THIRD_PARTY_DOMAIN_INITIAL_WHITELIST -> requestSubList.setText(R.string.third_party_domain_initial_whitelist)
249 BlocklistHelper.MAIN_BLACKLIST -> requestSubList.setText(R.string.main_blacklist)
250 BlocklistHelper.INITIAL_BLACKLIST -> requestSubList.setText(R.string.initial_blacklist)
251 BlocklistHelper.FINAL_BLACKLIST -> requestSubList.setText(R.string.final_blacklist)
252 BlocklistHelper.DOMAIN_BLACKLIST -> requestSubList.setText(R.string.domain_blacklist)
253 BlocklistHelper.DOMAIN_INITIAL_BLACKLIST -> requestSubList.setText(R.string.domain_initial_blacklist)
254 BlocklistHelper.DOMAIN_FINAL_BLACKLIST -> requestSubList.setText(R.string.domain_final_blacklist)
255 BlocklistHelper.DOMAIN_REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.domain_regular_expression_blacklist)
256 BlocklistHelper.THIRD_PARTY_BLACKLIST -> requestSubList.setText(R.string.third_party_blacklist)
257 BlocklistHelper.THIRD_PARTY_INITIAL_BLACKLIST -> requestSubList.setText(R.string.third_party_initial_blacklist)
258 BlocklistHelper.THIRD_PARTY_DOMAIN_BLACKLIST -> requestSubList.setText(R.string.third_party_domain_blacklist)
259 BlocklistHelper.THIRD_PARTY_DOMAIN_INITIAL_BLACKLIST -> requestSubList.setText(R.string.third_party_domain_initial_blacklist)
260 BlocklistHelper.THIRD_PARTY_REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.third_party_regular_expression_blacklist)
261 BlocklistHelper.THIRD_PARTY_DOMAIN_REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.third_party_domain_regular_expression_blacklist)
262 BlocklistHelper.REGULAR_EXPRESSION_BLACKLIST -> requestSubList.setText(R.string.regular_expression_blacklist)
266 // Return the alert dialog.