2 * Copyright 2018-2023 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android 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 Android 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 Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.activities
22 import android.content.Context
23 import android.database.Cursor
24 import android.database.MatrixCursor
25 import android.os.Bundle
26 import android.view.View
27 import android.view.WindowManager
28 import android.widget.AdapterView
29 import android.widget.ArrayAdapter
30 import android.widget.ListView
31 import android.widget.Spinner
32 import android.widget.TextView
34 import androidx.appcompat.app.ActionBar
35 import androidx.appcompat.app.AppCompatActivity
36 import androidx.appcompat.widget.Toolbar
37 import androidx.cursoradapter.widget.ResourceCursorAdapter
38 import androidx.fragment.app.DialogFragment
39 import androidx.preference.PreferenceManager
41 import com.stoutner.privacybrowser.R
42 import com.stoutner.privacybrowser.adapters.RequestsArrayAdapter
43 import com.stoutner.privacybrowser.dialogs.ViewRequestDialog.Companion.request
44 import com.stoutner.privacybrowser.dialogs.ViewRequestDialog.ViewRequestListener
45 import com.stoutner.privacybrowser.helpers.BlocklistHelper
47 // Define the public constants.
48 const val BLOCK_ALL_THIRD_PARTY_REQUESTS = "block_all_third_party_requests"
50 // Define the private class constants.
51 private const val LISTVIEW_POSITION = "listview_position"
53 class RequestsActivity : AppCompatActivity(), ViewRequestListener {
55 // The resource requests are populated by `MainWebViewActivity` before `RequestsActivity` is launched.
56 var resourceRequests: List<Array<String>>? = null
59 // Define the class views.
60 private lateinit var requestsListView: ListView
62 public override fun onCreate(savedInstanceState: Bundle?) {
63 // Get a handle for the shared preferences.
64 val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
66 // Get the preferences.
67 val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
68 val bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
70 // Disable screenshots if not allowed.
71 if (!allowScreenshots) {
72 window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
75 // Run the default commands.
76 super.onCreate(savedInstanceState)
78 // Get the launching intent
81 // Get the status of the third-party blocklist.
82 val blockAllThirdPartyRequests = intent.getBooleanExtra(BLOCK_ALL_THIRD_PARTY_REQUESTS, false)
84 // Set the content view.
86 setContentView(R.layout.requests_bottom_appbar)
88 setContentView(R.layout.requests_top_appbar)
91 // Get a handle for the toolbar.
92 val toolbar = findViewById<Toolbar>(R.id.requests_toolbar)
94 // Set the support action bar.
95 setSupportActionBar(toolbar)
97 // Get a handle for the app bar.
98 val appBar = supportActionBar!!
100 // Set the app bar custom view.
101 appBar.setCustomView(R.layout.spinner)
103 // Display the back arrow in the app bar.
104 appBar.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM or ActionBar.DISPLAY_HOME_AS_UP
106 // Get handles for the views.
107 val appBarSpinner = findViewById<Spinner>(R.id.spinner)
108 requestsListView = findViewById(R.id.requests_listview)
110 // Initialize the resource array lists. A list is needed for all the resource requests, or the activity can crash if `MainWebViewActivity.resourceRequests` is modified after the activity loads.
111 val allResourceRequests: MutableList<Array<String>> = ArrayList()
112 val defaultResourceRequests: MutableList<Array<String>> = ArrayList()
113 val allowedResourceRequests: MutableList<Array<String>> = ArrayList()
114 val thirdPartyResourceRequests: MutableList<Array<String>> = ArrayList()
115 val blockedResourceRequests: MutableList<Array<String>> = ArrayList()
117 // Populate the resource array lists.
118 for (request in resourceRequests!!) {
119 // Add the request to the list of all requests.
120 allResourceRequests.add(request)
122 when (request[BlocklistHelper.REQUEST_DISPOSITION]) {
123 BlocklistHelper.REQUEST_DEFAULT -> {
124 // Add the request to the list of default requests.
125 defaultResourceRequests.add(request)
128 BlocklistHelper.REQUEST_ALLOWED -> {
129 // Add the request to the list of allowed requests.
130 allowedResourceRequests.add(request)
133 BlocklistHelper.REQUEST_THIRD_PARTY -> {
134 // Add the request to the list of third-party requests.
135 thirdPartyResourceRequests.add(request)
138 BlocklistHelper.REQUEST_BLOCKED -> {
139 // Add the request to the list of blocked requests.
140 blockedResourceRequests.add(request)
145 // Setup a matrix cursor for the resource lists.
146 val spinnerCursor = MatrixCursor(arrayOf("_id", "Requests"))
147 spinnerCursor.addRow(arrayOf<Any>(0, getString(R.string.all) + " - " + allResourceRequests.size))
148 spinnerCursor.addRow(arrayOf<Any>(1, getString(R.string.default_label) + " - " + defaultResourceRequests.size))
149 spinnerCursor.addRow(arrayOf<Any>(2, getString(R.string.allowed_plural) + " - " + allowedResourceRequests.size))
150 if (blockAllThirdPartyRequests)
151 spinnerCursor.addRow(arrayOf<Any>(3, getString(R.string.third_party_plural) + " - " + thirdPartyResourceRequests.size))
152 spinnerCursor.addRow(arrayOf<Any>(4, getString(R.string.blocked_plural) + " - " + blockedResourceRequests.size))
154 // Create a resource cursor adapter for the spinner.
155 val spinnerCursorAdapter: ResourceCursorAdapter = object : ResourceCursorAdapter(this, R.layout.requests_appbar_spinner_item, spinnerCursor, 0) {
156 override fun bindView(view: View, context: Context, cursor: Cursor) {
157 // Get a handle for the spinner item text view.
158 val spinnerItemTextView = view.findViewById<TextView>(R.id.spinner_item_textview)
160 // Set the text view to display the resource list.
161 spinnerItemTextView.text = cursor.getString(1)
165 // Set the resource cursor adapter drop down view resource.
166 spinnerCursorAdapter.setDropDownViewResource(R.layout.requests_appbar_spinner_dropdown_item)
168 // Set the app bar spinner adapter.
169 appBarSpinner.adapter = spinnerCursorAdapter
171 // Get a handle for the context.
172 val context: Context = this
174 // Handle clicks on the spinner dropdown.
175 appBarSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
176 override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
179 // Get an adapter for all the requests.
180 val allResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, allResourceRequests)
182 // Display the adapter in the list view.
183 requestsListView.adapter = allResourceRequestsArrayAdapter
187 // Get an adapter for the default requests.
188 val defaultResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, defaultResourceRequests)
190 // Display the adapter in the list view.
191 requestsListView.adapter = defaultResourceRequestsArrayAdapter
195 // Get an adapter for the allowed requests.
196 val allowedResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, allowedResourceRequests)
198 // Display the adapter in the list view.
199 requestsListView.adapter = allowedResourceRequestsArrayAdapter
203 // Get an adapter for the third-party requests.
204 val thirdPartyResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, thirdPartyResourceRequests)
206 //Display the adapter in the list view.
207 requestsListView.adapter = thirdPartyResourceRequestsArrayAdapter
211 // Get an adapter for the blocked requests.
212 val blockedResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, blockedResourceRequests)
214 // Display the adapter in the list view.
215 requestsListView.adapter = blockedResourceRequestsArrayAdapter
220 override fun onNothingSelected(parent: AdapterView<*>?) {
225 // Create an array adapter with the list of the resource requests.
226 val resourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, allResourceRequests)
228 // Populate the list view with the resource requests adapter.
229 requestsListView.adapter = resourceRequestsArrayAdapter
231 // Listen for taps on entries in the list view.
232 requestsListView.onItemClickListener = AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, position: Int, _: Long ->
233 // Display the view request dialog. The list view is 0 based, so the position must be incremented by 1.
234 launchViewRequestDialog(position + 1)
237 // Check to see if the activity has been restarted.
238 if (savedInstanceState != null) {
239 // Scroll to the saved position.
240 requestsListView.post { requestsListView.setSelection(savedInstanceState.getInt(LISTVIEW_POSITION)) }
244 public override fun onSaveInstanceState(savedInstanceState: Bundle) {
245 // Run the default commands.
246 super.onSaveInstanceState(savedInstanceState)
248 // Get the listview position.
249 val listViewPosition = requestsListView.firstVisiblePosition
251 // Store the listview position in the bundle.
252 savedInstanceState.putInt(LISTVIEW_POSITION, listViewPosition)
255 override fun onPrevious(currentId: Int) {
256 // Show the previous dialog.
257 launchViewRequestDialog(currentId - 1)
260 override fun onNext(currentId: Int) {
261 // Show the next dialog.
262 launchViewRequestDialog(currentId + 1)
265 private fun launchViewRequestDialog(id: Int) {
266 // Determine if this is the last request in the list.
267 val isLastRequest = (id == requestsListView.count)
269 // Get the string array for the selected resource request. The resource requests list view is zero based. There is no need to check to make sure each string is not null because
270 @Suppress("UNCHECKED_CAST") val selectedRequestStringArray = (requestsListView.getItemAtPosition(id - 1) as Array<String>)
272 // Create a view request dialog.
273 val viewRequestDialogFragment: DialogFragment = request(id, isLastRequest, selectedRequestStringArray)
276 viewRequestDialogFragment.show(supportFragmentManager, getString(R.string.request_details))