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