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.REQUEST_ALLOWED
46 import com.stoutner.privacybrowser.helpers.REQUEST_BLOCKED
47 import com.stoutner.privacybrowser.helpers.REQUEST_DEFAULT
48 import com.stoutner.privacybrowser.helpers.REQUEST_DISPOSITION
49 import com.stoutner.privacybrowser.helpers.REQUEST_THIRD_PARTY
51 // Define the public constants.
52 const val BLOCK_ALL_THIRD_PARTY_REQUESTS = "block_all_third_party_requests"
54 // Define the private class constants.
55 private const val LISTVIEW_POSITION = "listview_position"
57 class RequestsActivity : AppCompatActivity(), ViewRequestListener {
59 // The resource requests are populated by `MainWebViewActivity` before `RequestsActivity` is launched.
60 var resourceRequests: List<Array<String>>? = null
63 // Define the class views.
64 private lateinit var requestsListView: ListView
66 public override fun onCreate(savedInstanceState: Bundle?) {
67 // Get a handle for the shared preferences.
68 val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
70 // Get the preferences.
71 val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
72 val bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
74 // Disable screenshots if not allowed.
75 if (!allowScreenshots) {
76 window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
79 // Run the default commands.
80 super.onCreate(savedInstanceState)
82 // Get the launching intent
85 // Get the status of the third-party filter list.
86 val blockAllThirdPartyRequests = intent.getBooleanExtra(BLOCK_ALL_THIRD_PARTY_REQUESTS, false)
88 // Set the content view.
90 setContentView(R.layout.requests_bottom_appbar)
92 setContentView(R.layout.requests_top_appbar)
95 // Get a handle for the toolbar.
96 val toolbar = findViewById<Toolbar>(R.id.requests_toolbar)
98 // Set the support action bar.
99 setSupportActionBar(toolbar)
101 // Get a handle for the app bar.
102 val appBar = supportActionBar!!
104 // Set the app bar custom view.
105 appBar.setCustomView(R.layout.spinner)
107 // Display the back arrow in the app bar.
108 appBar.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM or ActionBar.DISPLAY_HOME_AS_UP
110 // Get handles for the views.
111 val appBarSpinner = findViewById<Spinner>(R.id.spinner)
112 requestsListView = findViewById(R.id.requests_listview)
114 // 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.
115 val allResourceRequests: MutableList<Array<String>> = ArrayList()
116 val defaultResourceRequests: MutableList<Array<String>> = ArrayList()
117 val allowedResourceRequests: MutableList<Array<String>> = ArrayList()
118 val thirdPartyResourceRequests: MutableList<Array<String>> = ArrayList()
119 val blockedResourceRequests: MutableList<Array<String>> = ArrayList()
121 // Populate the resource array lists.
122 for (request in resourceRequests!!) {
123 // Add the request to the list of all requests.
124 allResourceRequests.add(request)
126 when (request[REQUEST_DISPOSITION]) {
128 // Add the request to the list of default requests.
129 defaultResourceRequests.add(request)
133 // Add the request to the list of allowed requests.
134 allowedResourceRequests.add(request)
137 REQUEST_THIRD_PARTY -> {
138 // Add the request to the list of third-party requests.
139 thirdPartyResourceRequests.add(request)
143 // Add the request to the list of blocked requests.
144 blockedResourceRequests.add(request)
149 // Setup a matrix cursor for the resource lists.
150 val spinnerCursor = MatrixCursor(arrayOf("_id", "Requests"))
151 spinnerCursor.addRow(arrayOf<Any>(0, getString(R.string.all) + " - " + allResourceRequests.size))
152 spinnerCursor.addRow(arrayOf<Any>(1, getString(R.string.default_label) + " - " + defaultResourceRequests.size))
153 spinnerCursor.addRow(arrayOf<Any>(2, getString(R.string.allowed_plural) + " - " + allowedResourceRequests.size))
154 if (blockAllThirdPartyRequests)
155 spinnerCursor.addRow(arrayOf<Any>(3, getString(R.string.third_party_plural) + " - " + thirdPartyResourceRequests.size))
156 spinnerCursor.addRow(arrayOf<Any>(4, getString(R.string.blocked_plural) + " - " + blockedResourceRequests.size))
158 // Create a resource cursor adapter for the spinner.
159 val spinnerCursorAdapter: ResourceCursorAdapter = object : ResourceCursorAdapter(this, R.layout.requests_appbar_spinner_item, spinnerCursor, 0) {
160 override fun bindView(view: View, context: Context, cursor: Cursor) {
161 // Get a handle for the spinner item text view.
162 val spinnerItemTextView = view.findViewById<TextView>(R.id.spinner_item_textview)
164 // Set the text view to display the resource list.
165 spinnerItemTextView.text = cursor.getString(1)
169 // Set the resource cursor adapter drop down view resource.
170 spinnerCursorAdapter.setDropDownViewResource(R.layout.requests_appbar_spinner_dropdown_item)
172 // Set the app bar spinner adapter.
173 appBarSpinner.adapter = spinnerCursorAdapter
175 // Get a handle for the context.
176 val context: Context = this
178 // Handle clicks on the spinner dropdown.
179 appBarSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
180 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
183 // Get an adapter for all the requests.
184 val allResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, allResourceRequests)
186 // Display the adapter in the list view.
187 requestsListView.adapter = allResourceRequestsArrayAdapter
191 // Get an adapter for the default requests.
192 val defaultResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, defaultResourceRequests)
194 // Display the adapter in the list view.
195 requestsListView.adapter = defaultResourceRequestsArrayAdapter
199 // Get an adapter for the allowed requests.
200 val allowedResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, allowedResourceRequests)
202 // Display the adapter in the list view.
203 requestsListView.adapter = allowedResourceRequestsArrayAdapter
207 // Get an adapter for the third-party requests.
208 val thirdPartyResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, thirdPartyResourceRequests)
210 //Display the adapter in the list view.
211 requestsListView.adapter = thirdPartyResourceRequestsArrayAdapter
215 // Get an adapter for the blocked requests.
216 val blockedResourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, blockedResourceRequests)
218 // Display the adapter in the list view.
219 requestsListView.adapter = blockedResourceRequestsArrayAdapter
224 override fun onNothingSelected(parent: AdapterView<*>?) {
229 // Create an array adapter with the list of the resource requests.
230 val resourceRequestsArrayAdapter: ArrayAdapter<Array<String>> = RequestsArrayAdapter(context, allResourceRequests)
232 // Populate the list view with the resource requests adapter.
233 requestsListView.adapter = resourceRequestsArrayAdapter
235 // Listen for taps on entries in the list view.
236 requestsListView.onItemClickListener = AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, position: Int, _: Long ->
237 // Display the view request dialog. The list view is 0 based, so the position must be incremented by 1.
238 launchViewRequestDialog(position + 1)
241 // Check to see if the activity has been restarted.
242 if (savedInstanceState != null) {
243 // Scroll to the saved position.
244 requestsListView.post { requestsListView.setSelection(savedInstanceState.getInt(LISTVIEW_POSITION)) }
248 public override fun onSaveInstanceState(savedInstanceState: Bundle) {
249 // Run the default commands.
250 super.onSaveInstanceState(savedInstanceState)
252 // Get the listview position.
253 val listViewPosition = requestsListView.firstVisiblePosition
255 // Store the listview position in the bundle.
256 savedInstanceState.putInt(LISTVIEW_POSITION, listViewPosition)
259 override fun onPrevious(currentId: Int) {
260 // Show the previous dialog.
261 launchViewRequestDialog(currentId - 1)
264 override fun onNext(currentId: Int) {
265 // Show the next dialog.
266 launchViewRequestDialog(currentId + 1)
269 private fun launchViewRequestDialog(id: Int) {
270 // Determine if this is the last request in the list.
271 val isLastRequest = (id == requestsListView.count)
273 // 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
274 @Suppress("UNCHECKED_CAST") val selectedRequestStringArray = (requestsListView.getItemAtPosition(id - 1) as Array<String>)
276 // Create a view request dialog.
277 val viewRequestDialogFragment: DialogFragment = request(id, isLastRequest, selectedRequestStringArray)
280 viewRequestDialogFragment.show(supportFragmentManager, getString(R.string.request_details))