X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FMainWebViewActivity.java;h=097c8af9b883b443710a0fd3375af767829ece81;hp=8ae5e7add4755185260d7bc8a134736fcad66a36;hb=ffdec8106ad23f62ca529749ade99f51e336ce55;hpb=c1c9a0bf83ecef671356d554bb6e4927392b1cc8 diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index 8ae5e7ad..097c8af9 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -50,6 +50,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; +import android.os.Message; import android.preference.PreferenceManager; import android.print.PrintDocumentAdapter; import android.print.PrintManager; @@ -214,6 +215,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private ArrayList> easyPrivacy; private ArrayList> fanboysAnnoyanceList; private ArrayList> fanboysSocialList; + private ArrayList> ultraList; private ArrayList> ultraPrivacy; // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`. @@ -724,6 +726,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem easyPrivacyMenuItem = menu.findItem(R.id.easyprivacy); MenuItem fanboysAnnoyanceListMenuItem = menu.findItem(R.id.fanboys_annoyance_list); MenuItem fanboysSocialBlockingListMenuItem = menu.findItem(R.id.fanboys_social_blocking_list); + MenuItem ultraListMenuItem = menu.findItem(R.id.ultralist); MenuItem ultraPrivacyMenuItem = menu.findItem(R.id.ultraprivacy); MenuItem blockAllThirdPartyRequestsMenuItem = menu.findItem(R.id.block_all_third_party_requests); MenuItem fontSizeMenuItem = menu.findItem(R.id.font_size); @@ -758,11 +761,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the status of the menu item checkboxes. domStorageMenuItem.setChecked(currentWebView.getSettings().getDomStorageEnabled()); saveFormDataMenuItem.setChecked(currentWebView.getSettings().getSaveFormData()); // Form data can be removed once the minimum API >= 26. - easyListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)); - easyPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)); + easyListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST)); + easyPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY)); fanboysAnnoyanceListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)); fanboysSocialBlockingListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST)); - ultraPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)); + ultraListMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST)); + ultraPrivacyMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY)); blockAllThirdPartyRequestsMenuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)); swipeToRefreshMenuItem.setChecked(currentWebView.getSwipeToRefresh()); wideViewportMenuItem.setChecked(currentWebView.getSettings().getUseWideViewPort()); @@ -771,11 +775,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Initialize the display names for the blocklists with the number of blocked requests. blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + currentWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - easyListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASY_LIST) + " - " + getString(R.string.easylist)); - easyPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY) + " - " + getString(R.string.easyprivacy)); + easyListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASYLIST) + " - " + getString(R.string.easylist)); + easyPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.EASYPRIVACY) + " - " + getString(R.string.easyprivacy)); fanboysAnnoyanceListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST) + " - " + getString(R.string.fanboys_annoyance_list)); fanboysSocialBlockingListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST) + " - " + getString(R.string.fanboys_social_blocking_list)); - ultraPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY) + " - " + getString(R.string.ultraprivacy)); + ultraListMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.ULTRALIST) + " - " + getString(R.string.ultralist)); + ultraPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.ULTRAPRIVACY) + " - " + getString(R.string.ultraprivacy)); blockAllThirdPartyRequestsMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS) + " - " + getString(R.string.block_all_third_party_requests)); // Only modify third-party cookies if the API >= 21. @@ -929,23 +934,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled. @SuppressLint("SetJavaScriptEnabled") public boolean onOptionsItemSelected(MenuItem menuItem) { - // Reenter full screen browsing mode if it was interrupted by the options menu. - if (inFullScreenBrowsingMode) { - // Remove the translucent status flag. This is necessary so the root frame layout can fill the entire screen. - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - - FrameLayout rootFrameLayout = findViewById(R.id.root_framelayout); - - /* Hide the system bars. - * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen. - * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar. - * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen. - * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown. - */ - rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - // Get the selected menu item ID. int menuItemId = menuItem.getItemId(); @@ -1289,10 +1277,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.easylist: // Toggle the EasyList status. - currentWebView.enableBlocklist(NestedScrollWebView.EASY_LIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)); + currentWebView.enableBlocklist(NestedScrollWebView.EASYLIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST)); // Update the menu checkbox. - menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST)); // Reload the current WebView. currentWebView.reload(); @@ -1302,10 +1290,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.easyprivacy: // Toggle the EasyPrivacy status. - currentWebView.enableBlocklist(NestedScrollWebView.EASY_PRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)); + currentWebView.enableBlocklist(NestedScrollWebView.EASYPRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY)); // Update the menu checkbox. - menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY)); // Reload the current WebView. currentWebView.reload(); @@ -1343,12 +1331,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; + case R.id.ultralist: + // Toggle the UltraList status. + currentWebView.enableBlocklist(NestedScrollWebView.ULTRALIST, !currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST)); + + // Update the menu checkbox. + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST)); + + // Reload the current WebView. + currentWebView.reload(); + + // Consume the event. + return true; + case R.id.ultraprivacy: // Toggle the UltraPrivacy status. - currentWebView.enableBlocklist(NestedScrollWebView.ULTRA_PRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)); + currentWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY, !currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY)); // Update the menu checkbox. - menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)); + menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY)); // Reload the current WebView. currentWebView.reload(); @@ -1940,7 +1941,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Create a string array for the blocklist versions. String[] blocklistVersions = new String[] {easyList.get(0).get(0)[0], easyPrivacy.get(0).get(0)[0], fanboysAnnoyanceList.get(0).get(0)[0], fanboysSocialList.get(0).get(0)[0], - ultraPrivacy.get(0).get(0)[0]}; + ultraList.get(0).get(0)[0], ultraPrivacy.get(0).get(0)[0]}; // Add the blocklist versions to the intent. aboutIntent.putExtra("blocklist_versions", blocklistVersions); @@ -2000,7 +2001,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Store the hit test result. final WebView.HitTestResult hitTestResult = currentWebView.getHitTestResult(); - // Create the URL strings. + // Define the URL strings. final String imageUrl; final String linkUrl; @@ -2026,19 +2027,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook menu.add(R.string.open_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> { // Load the link URL in a new tab. addNewTab(linkUrl); - return false; + + // Consume the event. + return true; }); // Add an Open with App entry. menu.add(R.string.open_with_app).setOnMenuItemClickListener((MenuItem item) -> { openWithApp(linkUrl); - return false; + + // Consume the event. + return true; }); // Add an Open with Browser entry. menu.add(R.string.open_with_browser).setOnMenuItemClickListener((MenuItem item) -> { openWithBrowser(linkUrl); - return false; + + // Consume the event. + return true; }); // Add a Copy URL entry. @@ -2048,7 +2055,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the `ClipData` as the clipboard's primary clip. clipboardManager.setPrimaryClip(srcAnchorTypeClipData); - return false; + + // Consume the event. + return true; }); // Add a Download URL entry. @@ -2083,7 +2092,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook downloadFileDialogFragment.show(fragmentManager, getString(R.string.download)); } } - return false; + + // Consume the event. + return true; }); // Add a Cancel entry, which by default closes the context menu. @@ -2110,7 +2121,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Make it so. startActivity(emailIntent); - return false; + + // Consume the event. + return true; }); // Add a Copy Email Address entry. @@ -2120,16 +2133,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the `ClipData` as the clipboard's primary clip. clipboardManager.setPrimaryClip(srcEmailTypeClipData); - return false; + + // Consume the event. + return true; }); // Add a `Cancel` entry, which by default closes the `ContextMenu`. menu.add(R.string.cancel); break; - // `IMAGE_TYPE` is an image. `SRC_IMAGE_ANCHOR_TYPE` is an image that is also a link. Privacy Browser processes them the same. + // `IMAGE_TYPE` is an image. case WebView.HitTestResult.IMAGE_TYPE: - case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE: // Get the image URL. imageUrl = hitTestResult.getExtra(); @@ -2140,16 +2154,21 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook menu.add(R.string.open_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> { // Load the image URL in a new tab. addNewTab(imageUrl); - return false; + + // Consume the event. + return true; }); // Add a View Image entry. menu.add(R.string.view_image).setOnMenuItemClickListener(item -> { + // Load the image in the current tab. loadUrl(imageUrl); - return false; + + // Consume the event. + return true; }); - // Add a `Download Image` entry. + // Add a Download Image entry. menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> { // Check if the download should be processed by an external app. if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app. @@ -2168,7 +2187,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Show the download location permission alert dialog. The permission will be requested when the dialog is closed. downloadLocationPermissionDialogFragment.show(fragmentManager, getString(R.string.download_location)); } else { // Show the permission request directly. - // Request the permission. The download dialog will be launched by `onRequestPermissionResult(). + // Request the permission. The download dialog will be launched by `onRequestPermissionResult()`. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_IMAGE_REQUEST_CODE); } } else { // The storage permission has already been granted. @@ -2179,32 +2198,149 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook downloadImageDialogFragment.show(fragmentManager, getString(R.string.download)); } } - return false; + + // Consume the event. + return true; }); - // Add a `Copy URL` entry. - menu.add(R.string.copy_url).setOnMenuItemClickListener(item -> { - // Save the image URL in a `ClipData`. - ClipData srcImageAnchorTypeClipData = ClipData.newPlainText(getString(R.string.url), imageUrl); + // Add a Copy URL entry. + menu.add(R.string.copy_url).setOnMenuItemClickListener((MenuItem item) -> { + // Save the image URL in a clip data. + ClipData imageTypeClipData = ClipData.newPlainText(getString(R.string.url), imageUrl); - // Set the `ClipData` as the clipboard's primary clip. - clipboardManager.setPrimaryClip(srcImageAnchorTypeClipData); - return false; + // Set the clip data as the clipboard's primary clip. + clipboardManager.setPrimaryClip(imageTypeClipData); + + // Consume the event. + return true; }); // Add an Open with App entry. menu.add(R.string.open_with_app).setOnMenuItemClickListener((MenuItem item) -> { + // Open the image URL with an external app. openWithApp(imageUrl); - return false; + + // Consume the event. + return true; }); // Add an Open with Browser entry. menu.add(R.string.open_with_browser).setOnMenuItemClickListener((MenuItem item) -> { + // Open the image URL with an external browser. openWithBrowser(imageUrl); - return false; + + // Consume the event. + return true; }); - // Add a `Cancel` entry, which by default closes the `ContextMenu`. + // Add a Cancel entry, which by default closes the context menu. + menu.add(R.string.cancel); + break; + + // `SRC_IMAGE_ANCHOR_TYPE` is an image that is also a link. + case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE: + // Get the image URL. + imageUrl = hitTestResult.getExtra(); + + // Instantiate a handler. + Handler handler = new Handler(); + + // Get a message from the handler. + Message message = handler.obtainMessage(); + + // Request the image details from the last touched node be returned in the message. + currentWebView.requestFocusNodeHref(message); + + // Get the link URL from the message data. + linkUrl = message.getData().getString("url"); + + // Set the link URL as the title of the context menu. + menu.setHeaderTitle(linkUrl); + + // Add an Open in New Tab entry. + menu.add(R.string.open_in_new_tab).setOnMenuItemClickListener((MenuItem item) -> { + // Load the link URL in a new tab. + addNewTab(linkUrl); + + // Consume the event. + return true; + }); + + // Add a View Image entry. + menu.add(R.string.view_image).setOnMenuItemClickListener((MenuItem item) -> { + // View the image in the current tab. + loadUrl(imageUrl); + + // Consume the event. + return true; + }); + + // Add a Download Image entry. + menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> { + // Check if the download should be processed by an external app. + if (sharedPreferences.getBoolean("download_with_external_app", false)) { // Download with an external app. + openUrlWithExternalApp(imageUrl); + } else { // Download with Android's download manager. + // Check to see if the storage permission has already been granted. + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { // The storage permission needs to be requested. + // Store the image URL for use by `onRequestPermissionResult()`. + downloadImageUrl = imageUrl; + + // Show a dialog if the user has previously denied the permission. + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first. + // Instantiate the download location permission alert dialog and set the download type to DOWNLOAD_IMAGE. + DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_IMAGE); + + // Show the download location permission alert dialog. The permission will be requested when the dialog is closed. + downloadLocationPermissionDialogFragment.show(fragmentManager, getString(R.string.download_location)); + } else { // Show the permission request directly. + // Request the permission. The download dialog will be launched by `onRequestPermissionResult()`. + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, DOWNLOAD_IMAGE_REQUEST_CODE); + } + } else { // The storage permission has already been granted. + // Get a handle for the download image alert dialog. + DialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(imageUrl); + + // Show the download image alert dialog. + downloadImageDialogFragment.show(fragmentManager, getString(R.string.download)); + } + } + + // Consume the event. + return true; + }); + + // Add a Copy URL entry. + menu.add(R.string.copy_url).setOnMenuItemClickListener((MenuItem item) -> { + // Save the link URL in a clip data. + ClipData srcImageAnchorTypeClipData = ClipData.newPlainText(getString(R.string.url), linkUrl); + + // Set the clip data as the clipboard's primary clip. + clipboardManager.setPrimaryClip(srcImageAnchorTypeClipData); + + // Consume the event. + return true; + }); + + // Add an Open with App entry. + menu.add(R.string.open_with_app).setOnMenuItemClickListener((MenuItem item) -> { + // Open the link URL with an external app. + openWithApp(linkUrl); + + // Consume the event. + return true; + }); + + // Add an Open with Browser entry. + menu.add(R.string.open_with_browser).setOnMenuItemClickListener((MenuItem item) -> { + // Open the link URL with an external browser. + openWithBrowser(linkUrl); + + // Consume the event. + return true; + }); + + // Add a cancel entry, which by default closes the context menu. menu.add(R.string.cancel); break; } @@ -3601,15 +3737,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nestedScrollWebView.getSettings().setDomStorageEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1); // Form data can be removed once the minimum API >= 26. boolean saveFormData = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1); - nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_LIST, + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYLIST, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST)) == 1); - nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_PRIVACY, + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYPRIVACY, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY)) == 1); nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST)) == 1); nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST)) == 1); - nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRA_PRIVACY, + nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRALIST, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST)) == 1); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY)) == 1); nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1); @@ -3823,11 +3960,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook boolean defaultThirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false); nestedScrollWebView.getSettings().setDomStorageEnabled(sharedPreferences.getBoolean("dom_storage", false)); boolean saveFormData = sharedPreferences.getBoolean("save_form_data", false); // Form data can be removed once the minimum API >= 26. - nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_LIST, sharedPreferences.getBoolean("easylist", true)); - nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASY_PRIVACY, sharedPreferences.getBoolean("easyprivacy", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYLIST, sharedPreferences.getBoolean("easylist", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYPRIVACY, sharedPreferences.getBoolean("easyprivacy", true)); nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST, sharedPreferences.getBoolean("fanboys_annoyance_list", true)); nestedScrollWebView.enableBlocklist(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST, sharedPreferences.getBoolean("fanboys_social_blocking_list", true)); - nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRA_PRIVACY, sharedPreferences.getBoolean("ultraprivacy", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRALIST, sharedPreferences.getBoolean("ultralist", true)); + nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY, sharedPreferences.getBoolean("ultraprivacy", true)); nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, sharedPreferences.getBoolean("block_all_third_party_requests", false)); nestedScrollWebView.setNightMode(sharedPreferences.getBoolean("night_mode", false)); @@ -4216,8 +4354,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Flag the intent to open in a new task. openWithAppIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - // Show the chooser. - startActivity(openWithAppIntent); + try { + // Show the chooser. + startActivity(openWithAppIntent); + } catch (ActivityNotFoundException exception) { + // Show a snackbar with the error. + Snackbar.make(currentWebView, getString(R.string.error) + " " + exception, Snackbar.LENGTH_INDEFINITE).show(); + } } private void openWithBrowser(String url) { @@ -4230,8 +4373,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Flag the intent to open in a new task. openWithBrowserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - // Show the chooser. - startActivity(openWithBrowserIntent); + try { + // Show the chooser. + startActivity(openWithBrowserIntent); + } catch (ActivityNotFoundException exception) { + // Show a snackbar with the error. + Snackbar.make(currentWebView, getString(R.string.error) + " " + exception, Snackbar.LENGTH_INDEFINITE).show(); + } } private String sanitizeUrl(String url) { @@ -4279,7 +4427,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook easyPrivacy = combinedBlocklists.get(1); fanboysAnnoyanceList = combinedBlocklists.get(2); fanboysSocialList = combinedBlocklists.get(3); - ultraPrivacy = combinedBlocklists.get(4); + ultraList = combinedBlocklists.get(4); + ultraPrivacy = combinedBlocklists.get(5); // Add the first tab. addNewTab(""); @@ -4852,13 +5001,26 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } }); - // Update the status of swipe to refresh based on the scroll position of the nested scroll WebView. + // Update the status of swipe to refresh based on the scroll position of the nested scroll WebView. Also reinforce full screen browsing mode. // Once the minimum API >= 23 this can be replaced with `nestedScrollWebView.setOnScrollChangeListener()`. nestedScrollWebView.getViewTreeObserver().addOnScrollChangedListener(() -> { if (nestedScrollWebView.getSwipeToRefresh()) { // Only enable swipe to refresh if the WebView is scrolled to the top. swipeRefreshLayout.setEnabled(nestedScrollWebView.getScrollY() == 0); } + + // Reinforce the system UI visibility flags if in full screen browsing mode. + // This hides the status and navigation bars, which are displayed if other elements are shown, like dialog boxes, the options menu, or the keyboard. + if (inFullScreenBrowsingMode) { + /* Hide the system bars. + * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen. + * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar. + * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen. + * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown. + */ + rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } }); // Set the web chrome client. @@ -5284,8 +5446,48 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook return emptyWebResourceResponse; } + // Check UltraList if it is enabled. + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.ULTRALIST)) { + // Check the URL against UltraList. + String[] ultraListResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, ultraList); + + // Process the UltraList results. + if (ultraListResults[0].equals(BlocklistHelper.REQUEST_BLOCKED)) { // The resource request matched UltraLists's blacklist. + // Add the result to the resource requests. + nestedScrollWebView.addResourceRequest(new String[] {ultraListResults[0], ultraListResults[1], ultraListResults[2], ultraListResults[3], ultraListResults[4], ultraListResults[5]}); + + // Increment the blocked requests counters. + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.ULTRALIST); + + // Update the titles of the blocklist menu items if the WebView is currently displayed. + if (webViewDisplayed) { + // Updating the UI must be run from the UI thread. + activity.runOnUiThread(() -> { + // Update the menu item titles. + navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); + + // Update the options menu if it has been populated. + if (optionsMenu != null) { + optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); + optionsMenu.findItem(R.id.ultralist).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRALIST) + " - " + getString(R.string.ultralist)); + } + }); + } + + // The resource request was blocked. Return an empty web resource response. + return emptyWebResourceResponse; + } else if (ultraListResults[0].equals(BlocklistHelper.REQUEST_ALLOWED)) { // The resource request matched UltraList's whitelist. + // Add a whitelist entry to the resource requests array. + nestedScrollWebView.addResourceRequest(new String[] {ultraListResults[0], ultraListResults[1], ultraListResults[2], ultraListResults[3], ultraListResults[4], ultraListResults[5]}); + + // The resource request has been allowed by UltraPrivacy. `return null` loads the requested resource. + return null; + } + } + // Check UltraPrivacy if it is enabled. - if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)) { + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.ULTRAPRIVACY)) { // Check the URL against UltraPrivacy. String[] ultraPrivacyResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, ultraPrivacy); @@ -5297,7 +5499,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.ULTRA_PRIVACY); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.ULTRAPRIVACY); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -5309,7 +5511,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the options menu if it has been populated. if (optionsMenu != null) { optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - optionsMenu.findItem(R.id.ultraprivacy).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY) + " - " + getString(R.string.ultraprivacy)); + optionsMenu.findItem(R.id.ultraprivacy).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRAPRIVACY) + " - " + getString(R.string.ultraprivacy)); } }); } @@ -5327,7 +5529,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Check EasyList if it is enabled. - if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)) { + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASYLIST)) { // Check the URL against EasyList. String[] easyListResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyList); @@ -5338,7 +5540,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_LIST); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASYLIST); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -5350,7 +5552,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the options menu if it has been populated. if (optionsMenu != null) { optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - optionsMenu.findItem(R.id.easylist).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_LIST) + " - " + getString(R.string.easylist)); + optionsMenu.findItem(R.id.easylist).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASYLIST) + " - " + getString(R.string.easylist)); } }); } @@ -5364,7 +5566,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } // Check EasyPrivacy if it is enabled. - if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)) { + if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASYPRIVACY)) { // Check the URL against EasyPrivacy. String[] easyPrivacyResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyPrivacy); @@ -5376,7 +5578,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Increment the blocked requests counters. nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS); - nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_PRIVACY); + nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASYPRIVACY); // Update the titles of the blocklist menu items if the WebView is currently displayed. if (webViewDisplayed) { @@ -5388,7 +5590,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update the options menu if it has been populated. if (optionsMenu != null) { optionsMenu.findItem(R.id.blocklists).setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS)); - optionsMenu.findItem(R.id.easyprivacy).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY) + " - " + getString(R.string.easyprivacy)); + optionsMenu.findItem(R.id.easyprivacy).setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASYPRIVACY) + " - " + getString(R.string.easyprivacy)); } }); }