]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
Update Download with External App summary. https://redmine.stoutner.com/issues/921
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.java
index a7cbffb53280f5ee365ef22be77fdd4b17e17cb5..1ee31db40a03cb8dfe9996eacfeaa79140aa230e 100644 (file)
@@ -190,9 +190,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         WebViewTabFragment.NewTabListener {
 
     // Define the public static variables.
-    public static ExecutorService executorService = Executors.newFixedThreadPool(4);
+    public static final ExecutorService executorService = Executors.newFixedThreadPool(4);
     public static String orbotStatus = "unknown";
-    public static ArrayList<PendingDialog> pendingDialogsArrayList =  new ArrayList<>();
+    public static final ArrayList<PendingDialog> pendingDialogsArrayList =  new ArrayList<>();
     public static String proxyMode = ProxyHelper.NONE;
 
     // Declare the public static variables.
@@ -370,7 +370,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private Activity resultLauncherActivityHandle;
 
     // Define the save URL activity result launcher.  It must be defined before `onCreate()` is run or the app will crash.
-    private final ActivityResultLauncher<String> saveUrlActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument("text/*"),
+    private final ActivityResultLauncher<String> saveUrlActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.CreateDocument("*/*"),
             new ActivityResultCallback<Uri>() {
                 @Override
                 public void onActivityResult(Uri fileUri) {
@@ -391,11 +391,30 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 public void onActivityResult(Uri fileUri) {
                     // Only save the webpage archive if the file URI is not null, which happens if the user exited the file picker by pressing back.
                     if (fileUri != null) {
+                        // Initialize the file name string from the file URI last path segment.
+                        String temporaryFileNameString = fileUri.getLastPathSegment();
+
+                        // Query the exact file name if the API >= 26.
+                        if (Build.VERSION.SDK_INT >= 26) {
+                            // Get a cursor from the content resolver.
+                            Cursor contentResolverCursor = resultLauncherActivityHandle.getContentResolver().query(fileUri, null, null, null);
+
+                            // Move to the fist row.
+                            contentResolverCursor.moveToFirst();
+
+                            // Get the file name from the cursor.
+                            temporaryFileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
+
+                            // Close the cursor.
+                            contentResolverCursor.close();
+                        }
+
+                        // Save the final file name string so it can be used inside the lambdas.  This will no longer be needed once this activity has transitioned to Kotlin.
+                        String finalFileNameString = temporaryFileNameString;
+
                         try {
                             // Create a temporary MHT file.
                             File temporaryMhtFile = File.createTempFile("temporary_mht_file", ".mht", getCacheDir());
-
-                            // Save the temporary MHT file.
                             currentWebView.saveWebArchive(temporaryMhtFile.toString(), false, callbackValue -> {
                                 if (callbackValue != null) {  // The temporary MHT file was saved successfully.
                                     try {
@@ -420,29 +439,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                                         mhtOutputStream.close();
                                         temporaryMhtFileInputStream.close();
 
-                                        // Initialize the file name string from the file URI last path segment.
-                                        String fileNameString = fileUri.getLastPathSegment();
-
-                                        // Query the exact file name if the API >= 26.
-                                        if (Build.VERSION.SDK_INT >= 26) {
-                                            // Get a cursor from the content resolver.
-                                            Cursor contentResolverCursor = resultLauncherActivityHandle.getContentResolver().query(fileUri, null, null, null);
-
-                                            // Move to the fist row.
-                                            contentResolverCursor.moveToFirst();
-
-                                            // Get the file name from the cursor.
-                                            fileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
-
-                                            // Close the cursor.
-                                            contentResolverCursor.close();
-                                        }
-
                                         // Display a snackbar.
-                                        Snackbar.make(currentWebView, getString(R.string.file_saved) + "  " + fileNameString, Snackbar.LENGTH_SHORT).show();
+                                        Snackbar.make(currentWebView, getString(R.string.saved, finalFileNameString), Snackbar.LENGTH_SHORT).show();
                                     } catch (Exception exception) {
                                         // Display a snackbar with the exception.
-                                        Snackbar.make(currentWebView, getString(R.string.error_saving_file) + "  " + exception, Snackbar.LENGTH_INDEFINITE).show();
+                                        Snackbar.make(currentWebView, getString(R.string.error_saving_file, finalFileNameString, exception), Snackbar.LENGTH_INDEFINITE).show();
                                     } finally {
                                         // Delete the temporary MHT file.
                                         //noinspection ResultOfMethodCallIgnored
@@ -450,12 +451,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                                     }
                                 } else {  // There was an unspecified error while saving the temporary MHT file.
                                     // Display an error snackbar.
-                                    Snackbar.make(currentWebView, getString(R.string.error_saving_file), Snackbar.LENGTH_INDEFINITE).show();
+                                    Snackbar.make(currentWebView, getString(R.string.error_saving_file, finalFileNameString, getString(R.string.unknown_error)), Snackbar.LENGTH_INDEFINITE).show();
                                 }
                             });
                         } catch (IOException ioException) {
                             // Display a snackbar with the IO exception.
-                            Snackbar.make(currentWebView, getString(R.string.error_saving_file) + "  " + ioException, Snackbar.LENGTH_INDEFINITE).show();
+                            Snackbar.make(currentWebView, getString(R.string.error_saving_file, finalFileNameString, ioException), Snackbar.LENGTH_INDEFINITE).show();
                         }
                     }
                 }
@@ -589,6 +590,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Initially disable the sliding drawers.  They will be enabled once the blocklists are loaded.
         drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
 
+        // Initially hide the user interface so that only the blocklist loading screen is shown (if reloading).
+        drawerLayout.setVisibility(View.GONE);
+
         // Initialize the web view pager adapter.
         webViewPagerAdapter = new WebViewPagerAdapter(getSupportFragmentManager());
 
@@ -2233,6 +2237,15 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
             // Make it so.
             startActivity(logcatIntent);
+        } else if (menuItemId == R.id.webview_devtools) {  // WebView Dev.
+            // Create a WebView DevTools intent.
+            Intent webViewDevToolsIntent = new Intent("com.android.webview.SHOW_DEV_UI");
+
+            // Launch as a new task so that the WebView DevTools and Privacy Browser show as a separate windows in the recent tasks list.
+            webViewDevToolsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            // Make it so.
+            startActivity(webViewDevToolsIntent);
         } else if (menuItemId == R.id.guide) {  // Guide.
             // Create an intent to launch the guide activity.
             Intent guideIntent = new Intent(this, GuideActivity.class);
@@ -2712,7 +2725,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Update the bookmarks cursor with the current contents of this folder.
         bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
 
-        // Update the `ListView`.
+        // Update the list view.
         bookmarksCursorAdapter.changeCursor(bookmarksCursor);
 
         // Scroll to the new folder.
@@ -2806,7 +2819,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Update the bookmarks cursor with the current contents of this folder.
         bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
 
-        // Update the `ListView`.
+        // Update the list view.
         bookmarksCursorAdapter.changeCursor(bookmarksCursor);
     }
 
@@ -3106,19 +3119,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Remove the lint warning below that the input method manager might be null.
         assert inputMethodManager != null;
 
-        // Initialize the gray foreground color spans for highlighting the URLs.
+        // Initialize the color spans for highlighting the URLs.
         initialGrayColorSpan = new ForegroundColorSpan(getColor(R.color.gray_500));
         finalGrayColorSpan = new ForegroundColorSpan(getColor(R.color.gray_500));
-
-        // Get the current theme status.
-        int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
-
-        // Set the red color span according to the theme.
-        if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
-            redColorSpan = new ForegroundColorSpan(getColor(R.color.red_a700));
-        } else {
-            redColorSpan = new ForegroundColorSpan(getColor(R.color.red_900));
-        }
+        redColorSpan = new ForegroundColorSpan(getColor(R.color.red_text));
 
         // Remove the formatting from the URL edit text when the user is editing the text.
         urlEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> {
@@ -3454,11 +3458,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 // Move the bookmark cursor to the first row.
                 bookmarkCursor.moveToFirst();
 
-                // Load the bookmark in a new tab but do not switch to the tab or close the drawer.
-                addNewTab(bookmarkCursor.getString(bookmarkCursor.getColumnIndexOrThrow(BookmarksDatabaseHelper.BOOKMARK_URL)), false);
+                // Load the bookmark in a new tab.
+                addNewTab(bookmarkCursor.getString(bookmarkCursor.getColumnIndexOrThrow(BookmarksDatabaseHelper.BOOKMARK_URL)), true);
 
-                // Display a snackbar.
-                Snackbar.make(drawerLayout, R.string.bookmark_opened_in_background, Snackbar.LENGTH_SHORT).show();
+                // Close the bookmarks drawer.
+                drawerLayout.closeDrawer(GravityCompat.END);
             }
 
             // Consume the event.
@@ -3797,7 +3801,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
 
             // Store the general preference information.
-            boolean defaultXRequestedWithHeader = sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true);
             String defaultFontSizeString = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value));
             String defaultUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value));
             boolean defaultSwipeToRefresh = sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true);
@@ -3843,7 +3846,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 nestedScrollWebView.setBlockAllThirdPartyRequests(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(
                         DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS)) == 1);
                 String userAgentName = currentDomainSettingsCursor.getString(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.USER_AGENT));
-                int xRequestedWithHeaderInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.X_REQUESTED_WITH_HEADER));
                 int fontSize = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.FONT_SIZE));
                 int swipeToRefreshInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
                 int webViewThemeInt = currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.WEBVIEW_THEME));
@@ -3883,24 +3885,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     nestedScrollWebView.getSettings().setSaveFormData(saveFormData);
                 }
 
-                // Set the X-Requested-With header.
-                switch (xRequestedWithHeaderInt) {
-                    case DomainsDatabaseHelper.SYSTEM_DEFAULT:
-                        if (defaultXRequestedWithHeader)
-                            nestedScrollWebView.setXRequestedWithHeader();
-                        else
-                            nestedScrollWebView.resetXRequestedWithHeader();
-                        break;
-
-                    case DomainsDatabaseHelper.ENABLED:
-                        nestedScrollWebView.setXRequestedWithHeader();
-                        break;
-
-                    case DomainsDatabaseHelper.DISABLED:
-                        nestedScrollWebView.resetXRequestedWithHeader();
-                        break;
-                }
-
                 // Apply the font size.
                 try {  // Try the specified font size to see if it is valid.
                     if (fontSize == 0) {  // Apply the default font size.
@@ -4131,12 +4115,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     nestedScrollWebView.getSettings().setSaveFormData(saveFormData);
                 }
 
-                // Store the X-Requested-With header status in the nested scroll WebView.
-                if (defaultXRequestedWithHeader)
-                    nestedScrollWebView.setXRequestedWithHeader();
-                else
-                    nestedScrollWebView.resetXRequestedWithHeader();
-
                 // Store the swipe to refresh status in the nested scroll WebView.
                 nestedScrollWebView.setSwipeToRefresh(defaultSwipeToRefresh);
 
@@ -4244,7 +4222,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
         // Load the URL if directed.  This makes sure that the domain settings are properly loaded before the URL.  By using `loadUrl()`, instead of `loadUrlFromBase()`, the Referer header will never be sent.
         if (loadUrl) {
-            nestedScrollWebView.loadUrl(url, nestedScrollWebView.getXRequestedWithHeader());
+            nestedScrollWebView.loadUrl(url);
         }
     }
 
@@ -4335,27 +4313,31 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 } else {
                     appBarLayout.setBackgroundResource(R.color.dark_blue_30);
                 }
+                // Get the package manager.
+                PackageManager packageManager = getPackageManager();
 
                 // Check to see if I2P is installed.
                 try {
-                    // Get the package manager.
-                    PackageManager packageManager = getPackageManager();
-
-                    // Check to see if I2P is in the list.  This will throw an error and drop to the catch section if it isn't installed.
+                    // Check to see if the F-Droid flavor is installed.  This will throw an error and drop to the catch section if it isn't installed.
                     packageManager.getPackageInfo("net.i2p.android.router", 0);
-                } catch (PackageManager.NameNotFoundException exception) {  // I2P is not installed.
-                    // Sow the I2P not installed dialog if it is not already displayed.
-                    if (getSupportFragmentManager().findFragmentByTag(getString(R.string.proxy_not_installed_dialog)) == null) {
-                        // Get a handle for the waiting for proxy alert dialog.
-                        DialogFragment i2pNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode);
+                } catch (PackageManager.NameNotFoundException fdroidException) {  // The F-Droid flavor is not installed.
+                    try {
+                        // Check to see if the Google Play flavor is installed.  This will throw an error and drop to the catch section if it isn't installed.
+                        packageManager.getPackageInfo("net.i2p.android", 0);
+                    } catch (PackageManager.NameNotFoundException googlePlayException) {  // The Google Play flavor is not installed.
+                        // Sow the I2P not installed dialog if it is not already displayed.
+                        if (getSupportFragmentManager().findFragmentByTag(getString(R.string.proxy_not_installed_dialog)) == null) {
+                            // Get a handle for the waiting for proxy alert dialog.
+                            DialogFragment i2pNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode);
 
-                        // Try to show the dialog.  Sometimes the window is not yet active if returning from Settings.
-                        try {
-                            // Display the I2P not installed alert dialog.
-                            i2pNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog));
-                        } catch (Exception i2pNotInstalledException) {
-                            // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
-                            pendingDialogsArrayList.add(new PendingDialog(i2pNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)));
+                            // Try to show the dialog.  Sometimes the window is not yet active if returning from Settings.
+                            try {
+                                // Display the I2P not installed alert dialog.
+                                i2pNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog));
+                            } catch (Exception i2pNotInstalledException) {
+                                // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
+                                pendingDialogsArrayList.add(new PendingDialog(i2pNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)));
+                            }
                         }
                     }
                 }