Teach resource requests to be tab aware.
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / activities / RequestsActivity.java
1 /*
2  * Copyright © 2018-2019 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 package com.stoutner.privacybrowser.activities;
21
22 import android.content.Context;
23 import android.content.SharedPreferences;
24 import android.database.Cursor;
25 import android.database.MatrixCursor;
26 import android.os.Bundle;
27 import android.preference.PreferenceManager;
28 import android.view.View;
29 import android.view.WindowManager;
30 import android.widget.AdapterView;
31 import android.widget.ArrayAdapter;
32 import android.widget.ListView;
33 import android.widget.ResourceCursorAdapter;
34 import android.widget.Spinner;
35 import android.widget.TextView;
36
37 import androidx.appcompat.app.ActionBar;
38 import androidx.appcompat.app.AppCompatActivity;
39 import androidx.appcompat.widget.Toolbar;  // The AndroidX toolbar must be used until the minimum API >= 21.
40 import androidx.fragment.app.DialogFragment;
41
42 import com.stoutner.privacybrowser.R;
43 import com.stoutner.privacybrowser.adapters.RequestsArrayAdapter;
44 import com.stoutner.privacybrowser.dialogs.ViewRequestDialog;
45 import com.stoutner.privacybrowser.helpers.BlockListHelper;
46
47 import java.util.ArrayList;
48 import java.util.List;
49
50 public class RequestsActivity extends AppCompatActivity implements ViewRequestDialog.ViewRequestListener {
51     // The resource requests are populated by `MainWebViewActivity` before `RequestsActivity` is launched.
52     public static ArrayList<String[]> resourceRequests;
53
54     // The list view is used in `onCreate()` and `launchViewRequestDialog()`.
55     private ListView requestsListView;
56
57     @Override
58     public void onCreate(Bundle savedInstanceState) {
59         // Get a handle for the shared preferences.
60         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
61
62         // Get the screenshot and theme preferences.
63         boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
64         boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
65
66         // Disable screenshots if not allowed.
67         if (!allowScreenshots) {
68             getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
69         }
70
71         // Set the activity theme.
72         if (darkTheme) {
73             setTheme(R.style.PrivacyBrowserDark_SecondaryActivity);
74         } else {
75             setTheme(R.style.PrivacyBrowserLight_SecondaryActivity);
76         }
77
78         // Run the default commands.
79         super.onCreate(savedInstanceState);
80
81         // Set the content view.
82         setContentView(R.layout.requests_coordinatorlayout);
83
84         // Use the AndroidX toolbar until the minimum API is >= 21.
85         Toolbar toolbar = findViewById(R.id.requests_toolbar);
86         setSupportActionBar(toolbar);
87
88         // Get a handle for the app bar and the list view.
89         ActionBar appBar = getSupportActionBar();
90         requestsListView = findViewById(R.id.requests_listview);
91
92         // Remove the incorrect lint warning that `appBar` might be null.
93         assert appBar != null;
94
95         // Display the spinner and the back arrow in the app bar.
96         appBar.setCustomView(R.layout.spinner);
97         appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_HOME_AS_UP);
98
99         // 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.
100         List<String[]> allResourceRequests = new ArrayList<>();
101         List<String[]> defaultResourceRequests = new ArrayList<>();
102         List<String[]> allowedResourceRequests = new ArrayList<>();
103         List<String[]> thirdPartyResourceRequests = new ArrayList<>();
104         List<String[]> blockedResourceRequests = new ArrayList<>();
105
106         // Populate the resource array lists.
107         for (String[] request : resourceRequests) {
108             switch (request[BlockListHelper.REQUEST_DISPOSITION]) {
109                 case BlockListHelper.REQUEST_DEFAULT:
110                     // Add the request to the list of all requests.
111                     allResourceRequests.add(request);
112
113                     // Add the request to the list of default requests.
114                     defaultResourceRequests.add(request);
115                     break;
116
117                 case BlockListHelper.REQUEST_ALLOWED:
118                     // Add the request to the list of all requests.
119                     allResourceRequests.add(request);
120
121                     // Add the request to the list of allowed requests.
122                     allowedResourceRequests.add(request);
123                     break;
124
125                 case BlockListHelper.REQUEST_THIRD_PARTY:
126                     // Add the request to the list of all requests.
127                     allResourceRequests.add(request);
128
129                     // Add the request to the list of third-party requests.
130                     thirdPartyResourceRequests.add(request);
131                     break;
132
133                 case BlockListHelper.REQUEST_BLOCKED:
134                     // Add the request to the list of all requests.
135                     allResourceRequests.add(request);
136
137                     // Add the request to the list of blocked requests.
138                     blockedResourceRequests.add(request);
139                     break;
140             }
141         }
142
143         // Setup a matrix cursor for the resource lists.
144         MatrixCursor spinnerCursor = new MatrixCursor(new String[]{"_id", "Requests"});
145         spinnerCursor.addRow(new Object[]{0, getString(R.string.all) + " - " + allResourceRequests.size()});
146         spinnerCursor.addRow(new Object[]{1, getString(R.string.default_label) + " - " + defaultResourceRequests.size()});
147         spinnerCursor.addRow(new Object[]{2, getString(R.string.allowed_plural) + " - " + allowedResourceRequests.size()});
148         if (MainWebViewActivity.blockAllThirdPartyRequests) {
149             spinnerCursor.addRow(new Object[]{3, getString(R.string.third_party_plural) + " - " + thirdPartyResourceRequests.size()});
150         }
151         spinnerCursor.addRow(new Object[]{4, getString(R.string.blocked_plural) + " - " + blockedResourceRequests.size()});
152
153         // Create a resource cursor adapter for the spinner.
154         ResourceCursorAdapter spinnerCursorAdapter = new ResourceCursorAdapter(this, R.layout.requests_appbar_spinner_item, spinnerCursor, 0) {
155             @Override
156             public void bindView(View view, Context context, Cursor cursor) {
157                 // Get a handle for the spinner item text view.
158                 TextView spinnerItemTextView = view.findViewById(R.id.spinner_item_textview);
159
160                 // Set the text view to display the resource list.
161                 spinnerItemTextView.setText(cursor.getString(1));
162             }
163         };
164
165         // Set the resource cursor adapter drop down view resource.
166         spinnerCursorAdapter.setDropDownViewResource(R.layout.requests_appbar_spinner_dropdown_item);
167
168         // Get a handle for the app bar spinner and set the adapter.
169         Spinner appBarSpinner = findViewById(R.id.spinner);
170         appBarSpinner.setAdapter(spinnerCursorAdapter);
171
172         // Handle clicks on the spinner dropdown.
173         appBarSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
174             @Override
175             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
176                 switch ((int) id) {
177                     case 0:  // All requests.
178                         // Get an adapter for all the request.
179                         ArrayAdapter<String[]> allResourceRequestsArrayAdapter = new RequestsArrayAdapter(getApplicationContext(), allResourceRequests);
180
181                         // Display the adapter in the list view.
182                         requestsListView.setAdapter(allResourceRequestsArrayAdapter);
183                         break;
184
185                     case 1:  // Default requests.
186                         // Get an adapter for the default requests.
187                         ArrayAdapter<String[]> defaultResourceRequestsArrayAdapter = new RequestsArrayAdapter(getApplicationContext(), defaultResourceRequests);
188
189                         // Display the adapter in the list view.
190                         requestsListView.setAdapter(defaultResourceRequestsArrayAdapter);
191                         break;
192
193                     case 2:  // Allowed requests.
194                         // Get an adapter for the allowed requests.
195                         ArrayAdapter<String[]> allowedResourceRequestsArrayAdapter = new RequestsArrayAdapter(getApplicationContext(), allowedResourceRequests);
196
197                         // Display the adapter in the list view.
198                         requestsListView.setAdapter(allowedResourceRequestsArrayAdapter);
199                         break;
200
201                     case 3:  // Third-party requests.
202                         // Get an adapter for the third-party requests.
203                         ArrayAdapter<String[]> thirdPartyResourceRequestsArrayAdapter = new RequestsArrayAdapter(getApplicationContext(), thirdPartyResourceRequests);
204
205                         //Display the adapter in the list view.
206                         requestsListView.setAdapter(thirdPartyResourceRequestsArrayAdapter);
207                         break;
208
209                     case 4:  // Blocked requests.
210                         // Get an adapter fo the blocked requests.
211                         ArrayAdapter<String[]> blockedResourceRequestsArrayAdapter = new RequestsArrayAdapter(getApplicationContext(), blockedResourceRequests);
212
213                         // Display the adapter in the list view.
214                         requestsListView.setAdapter(blockedResourceRequestsArrayAdapter);
215                         break;
216                 }
217             }
218
219             @Override
220             public void onNothingSelected(AdapterView<?> parent) {
221                 // Do nothing.
222             }
223         });
224
225         // Create an array adapter with the list of the resource requests.
226         ArrayAdapter<String[]> resourceRequestsArrayAdapter = new RequestsArrayAdapter(getApplicationContext(), allResourceRequests);
227
228         // Populate the list view with the resource requests adapter.
229         requestsListView.setAdapter(resourceRequestsArrayAdapter);
230
231         // Listen for taps on entries in the list view.
232         requestsListView.setOnItemClickListener((AdapterView<?> parent, View view, int position, long id) -> {
233             // Display the view request dialog.  The list view is 0 based, so the position must be incremented by 1.
234             launchViewRequestDialog(position + 1);
235         });
236     }
237
238     @Override
239     public void onPrevious(int id) {
240         // Show the previous dialog.
241         launchViewRequestDialog(id -1);
242     }
243
244     @Override
245     public void onNext(int id) {
246         // Show the next dialog.
247         launchViewRequestDialog(id + 1);
248     }
249
250     private void launchViewRequestDialog(int id) {
251         // Determine if this is the last request in the list.
252         boolean isLastRequest = (id == requestsListView.getCount());
253
254         // Get the string array for the selected resource request.  The resource requests list view is zero based.
255         String[] selectedRequestStringArray = (String[]) requestsListView.getItemAtPosition(id - 1);
256
257         // Remove the warning that `selectedRequest` might be null.
258         assert selectedRequestStringArray != null;
259
260         // Show the request detail dialog.
261         DialogFragment viewRequestDialogFragment = ViewRequestDialog.request(id, isLastRequest, selectedRequestStringArray);
262         viewRequestDialogFragment.show(getSupportFragmentManager(), getString(R.string.request_details));
263     }
264 }