+ // Upload files.
+ @Override
+ public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
+ // Show the file chooser if the device is running API >= 21.
+ if (Build.VERSION.SDK_INT >= 21) {
+ // Store the file path callback.
+ fileChooserCallback = filePathCallback;
+
+ // Create an intent to open a chooser based ont the file chooser parameters.
+ Intent fileChooserIntent = fileChooserParams.createIntent();
+
+ // Open the file chooser. Currently only one `startActivityForResult` exists in this activity, so the request code, used to differentiate them, is simply `0`.
+ startActivityForResult(fileChooserIntent, 0);
+ }
+ return true;
+ }
+ });
+
+ // Register `mainWebView` for a context menu. This is used to see link targets and download images.
+ registerForContextMenu(mainWebView);
+
+ // Allow the downloading of files.
+ mainWebView.setDownloadListener((String url, String userAgent, String contentDisposition, String mimetype, long contentLength) -> {
+ // Check to see if the WRITE_EXTERNAL_STORAGE permission has already been granted.
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
+ // The WRITE_EXTERNAL_STORAGE permission needs to be requested.
+
+ // Store the variables for future use by `onRequestPermissionsResult()`.
+ downloadUrl = url;
+ downloadContentDisposition = contentDisposition;
+ downloadContentLength = contentLength;
+
+ // 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.
+ // Get a handle for the download location permission alert dialog and set the download type to DOWNLOAD_FILE.
+ DialogFragment downloadLocationPermissionDialogFragment = DownloadLocationPermissionDialog.downloadType(DownloadLocationPermissionDialog.DOWNLOAD_FILE);
+
+ // Show the download location permission alert dialog. The permission will be requested when the the dialog is closed.
+ downloadLocationPermissionDialogFragment.show(getFragmentManager(), 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_FILE_REQUEST_CODE);
+ }
+ } else { // The WRITE_EXTERNAL_STORAGE permission has already been granted.
+ // Get a handle for the download file alert dialog.
+ AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength);
+
+ // Show the download file alert dialog.
+ downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
+ }
+ });
+
+ // Allow pinch to zoom.
+ mainWebView.getSettings().setBuiltInZoomControls(true);
+
+ // Hide zoom controls.
+ mainWebView.getSettings().setDisplayZoomControls(false);
+
+ // Set `mainWebView` to use a wide viewport. Otherwise, some web pages will be scrunched and some content will render outside the screen.
+ mainWebView.getSettings().setUseWideViewPort(true);
+
+ // Set `mainWebView` to load in overview mode (zoomed out to the maximum width).
+ mainWebView.getSettings().setLoadWithOverviewMode(true);
+
+ // Explicitly disable geolocation.
+ mainWebView.getSettings().setGeolocationEnabled(false);
+
+ // Initialize cookieManager.
+ cookieManager = CookieManager.getInstance();
+
+ // Replace the header that `WebView` creates for `X-Requested-With` with a null value. The default value is the application ID (com.stoutner.privacybrowser.standard).
+ customHeaders.put("X-Requested-With", "");
+
+ // Initialize the default preference values the first time the program is run. `this` is the context. `false` keeps this command from resetting any current preferences back to default.
+ PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
+
+ // Get the intent that started the app.
+ final Intent launchingIntent = getIntent();
+
+ // Extract the launching intent data as `launchingIntentUriData`.
+ final Uri launchingIntentUriData = launchingIntent.getData();
+
+ // Convert the launching intent URI data (if it exists) to a string and store it in `formattedUrlString`.
+ if (launchingIntentUriData != null) {
+ formattedUrlString = launchingIntentUriData.toString();
+ }
+
+ // Get a handle for the `Runtime`.
+ privacyBrowserRuntime = Runtime.getRuntime();
+
+ // Store the application's private data directory.
+ privateDataDirectoryString = getApplicationInfo().dataDir;
+ // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`.
+
+ // Initialize `inFullScreenBrowsingMode`, which is always false at this point because Privacy Browser never starts in full screen browsing mode.
+ inFullScreenBrowsingMode = false;
+
+ // Initialize AdView for the free flavor.
+ adView = findViewById(R.id.adview);
+
+ // Initialize the privacy settings variables.
+ javaScriptEnabled = false;
+ firstPartyCookiesEnabled = false;
+ thirdPartyCookiesEnabled = false;
+ domStorageEnabled = false;
+ saveFormDataEnabled = false;
+ nightMode = false;
+
+ // Initialize the WebView title.
+ webViewTitle = getString(R.string.no_title);
+
+ // Initialize the favorite icon bitmap. `ContextCompat` must be used until API >= 21.
+ Drawable favoriteIconDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.world);
+ BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable;
+ assert favoriteIconBitmapDrawable != null;
+ favoriteIconDefaultBitmap = favoriteIconBitmapDrawable.getBitmap();
+
+ // If the favorite icon is null, load the default.
+ if (favoriteIconBitmap == null) {
+ favoriteIconBitmap = favoriteIconDefaultBitmap;