]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java
Fix View Source crashing on release builds. https://redmine.stoutner.com/issues/642
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / ViewSourceActivity.java
diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java
deleted file mode 100644 (file)
index e4899ea..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright © 2017-2020 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.activities;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.preference.PreferenceManager;
-import android.text.Spanned;
-import android.text.style.ForegroundColorSpan;
-import android.util.TypedValue;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-import androidx.core.app.NavUtils;
-import androidx.fragment.app.DialogFragment;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-
-import com.google.android.material.snackbar.Snackbar;
-import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.dialogs.AboutViewSourceDialog;
-import com.stoutner.privacybrowser.helpers.ProxyHelper;
-import com.stoutner.privacybrowser.viewmodelfactories.WebViewSourceFactory;
-import com.stoutner.privacybrowser.viewmodels.WebViewSource;
-
-import java.net.Proxy;
-import java.util.Locale;
-
-public class ViewSourceActivity extends AppCompatActivity {
-    // `activity` is used in `onCreate()` and `goBack()`.
-    private Activity activity;
-
-    // The color spans are used in `onCreate()` and `highlightUrlText()`.
-    private ForegroundColorSpan redColorSpan;
-    private ForegroundColorSpan initialGrayColorSpan;
-    private ForegroundColorSpan finalGrayColorSpan;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        // Get a handle for the shared preferences.
-        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
-
-        // Get the screenshot preference.
-        boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
-
-        // Disable screenshots if not allowed.
-        if (!allowScreenshots) {
-            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
-        }
-
-        // Set the theme.
-        setTheme(R.style.PrivacyBrowser);
-
-        // Run the default commands.
-        super.onCreate(savedInstanceState);
-
-        // Get the launching intent
-        Intent intent = getIntent();
-
-        // Get the information from the intent.
-        String userAgent = intent.getStringExtra("user_agent");
-        String currentUrl = intent.getStringExtra("current_url");
-
-        // Remove the incorrect lint warning below that the user agent might be null.
-        assert userAgent != null;
-
-        // Store a handle for the current activity.
-        activity = this;
-
-        // Set the content view.
-        setContentView(R.layout.view_source_coordinatorlayout);
-
-        // Get a handle for the toolbar.
-        Toolbar toolbar = findViewById(R.id.view_source_toolbar);
-
-        // Set the support action bar.
-        setSupportActionBar(toolbar);
-
-        // Get a handle for the action bar.
-        final ActionBar actionBar = getSupportActionBar();
-
-        // Remove the incorrect lint warning that the action bar might be null.
-        assert actionBar != null;
-
-        // Add the custom layout to the action bar.
-        actionBar.setCustomView(R.layout.view_source_app_bar);
-        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
-
-        // Get handles for the views.
-        EditText urlEditText = findViewById(R.id.url_edittext);
-        TextView requestHeadersTextView = findViewById(R.id.request_headers);
-        TextView responseMessageTextView = findViewById(R.id.response_message);
-        TextView responseHeadersTextView = findViewById(R.id.response_headers);
-        TextView responseBodyTextView = findViewById(R.id.response_body);
-        ProgressBar progressBar = findViewById(R.id.progress_bar);
-        SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.view_source_swiperefreshlayout);
-
-        // Populate the URL text box.
-        urlEditText.setText(currentUrl);
-
-        // Initialize the gray foreground color spans for highlighting the URLs.  The deprecated `getResources()` must be used until API >= 23.
-        initialGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500));
-        finalGrayColorSpan = new ForegroundColorSpan(getResources().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(getResources().getColor(R.color.red_a700));
-        } else {
-            redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_900));
-        }
-
-        // Apply text highlighting to the URL.
-        highlightUrlText();
-
-        // Get a handle for the input method manager, which is used to hide the keyboard.
-        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-
-        // Remove the lint warning that the input method manager might be null.
-        assert inputMethodManager != null;
-
-        // Remove the formatting from the URL when the user is editing the text.
-        urlEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> {
-            if (hasFocus) {  // The user is editing `urlTextBox`.
-                // Remove the highlighting.
-                urlEditText.getText().removeSpan(redColorSpan);
-                urlEditText.getText().removeSpan(initialGrayColorSpan);
-                urlEditText.getText().removeSpan(finalGrayColorSpan);
-            } else {  // The user has stopped editing `urlTextBox`.
-                // Hide the soft keyboard.
-                inputMethodManager.hideSoftInputFromWindow(urlEditText.getWindowToken(), 0);
-
-                // Move to the beginning of the string.
-                urlEditText.setSelection(0);
-
-                // Reapply the highlighting.
-                highlightUrlText();
-            }
-        });
-
-        // Set the refresh color scheme according to the theme.
-        if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
-            swipeRefreshLayout.setColorSchemeResources(R.color.blue_700);
-        } else {
-            swipeRefreshLayout.setColorSchemeResources(R.color.violet_500);
-        }
-
-        // Initialize a color background typed value.
-        TypedValue colorBackgroundTypedValue = new TypedValue();
-
-        // Get the color background from the theme.
-        getTheme().resolveAttribute(android.R.attr.colorBackground, colorBackgroundTypedValue, true);
-
-        // Get the color background int from the typed value.
-        int colorBackgroundInt = colorBackgroundTypedValue.data;
-
-        // Set the swipe refresh background color.
-        swipeRefreshLayout.setProgressBackgroundColorSchemeColor(colorBackgroundInt);
-
-        // Get the Do Not Track status.
-        boolean doNotTrack = sharedPreferences.getBoolean("do_not_track", false);
-
-        // Instantiate a locale string.
-        String localeString;
-
-        // Populate the locale string.
-        if (Build.VERSION.SDK_INT >= 24) {  // SDK >= 24 has a list of locales.
-            // Get the list of locales.
-            LocaleList localeList = getResources().getConfiguration().getLocales();
-
-            // Initialize a string builder to extract the locales from the list.
-            StringBuilder localesStringBuilder = new StringBuilder();
-
-            // Initialize a `q` value, which is used by `WebView` to indicate the order of importance of the languages.
-            int q = 10;
-
-            // Populate the string builder with the contents of the locales list.
-            for (int i = 0; i < localeList.size(); i++) {
-                // Append a comma if there is already an item in the string builder.
-                if (i > 0) {
-                    localesStringBuilder.append(",");
-                }
-
-                // Get the locale from the list.
-                Locale locale = localeList.get(i);
-
-                // Add the locale to the string.  `locale` by default displays as `en_US`, but WebView uses the `en-US` format.
-                localesStringBuilder.append(locale.getLanguage());
-                localesStringBuilder.append("-");
-                localesStringBuilder.append(locale.getCountry());
-
-                // If not the first locale, append `;q=0.x`, which drops by .1 for each removal from the main locale until q=0.1.
-                if (q < 10) {
-                    localesStringBuilder.append(";q=0.");
-                    localesStringBuilder.append(q);
-                }
-
-                // Decrement `q` if it is greater than 1.
-                if (q > 1) {
-                    q--;
-                }
-
-                // Add a second entry for the language only portion of the locale.
-                localesStringBuilder.append(",");
-                localesStringBuilder.append(locale.getLanguage());
-
-                // Append `1;q=0.x`, which drops by .1 for each removal form the main locale until q=0.1.
-                localesStringBuilder.append(";q=0.");
-                localesStringBuilder.append(q);
-
-                // Decrement `q` if it is greater than 1.
-                if (q > 1) {
-                    q--;
-                }
-            }
-
-            // Store the populated string builder in the locale string.
-            localeString = localesStringBuilder.toString();
-        } else {  // SDK < 24 only has a primary locale.
-            // Store the locale in the locale string.
-            localeString = Locale.getDefault().toString();
-        }
-
-        // Instantiate the proxy helper.
-        ProxyHelper proxyHelper = new ProxyHelper();
-
-        // Get the current proxy.
-        Proxy proxy = proxyHelper.getCurrentProxy(this);
-
-        // Make the progress bar visible.
-        progressBar.setVisibility(View.VISIBLE);
-
-        // Set the progress bar to be indeterminate.
-        progressBar.setIndeterminate(true);
-
-        // Instantiate the WebView source factory.
-        ViewModelProvider.Factory webViewSourceFactory = new WebViewSourceFactory(currentUrl, userAgent, doNotTrack, localeString, proxy, MainWebViewActivity.executorService);
-
-        // Instantiate the WebView source view model class.
-        final WebViewSource webViewSource = new ViewModelProvider(this, webViewSourceFactory).get(WebViewSource.class);
-
-        // Create a source observer.
-        webViewSource.observeSource().observe(this, sourceStringArray -> {
-            // Populate the text views.  This can take a long time, and freezes the user interface, if the response body is particularly large.
-            requestHeadersTextView.setText(sourceStringArray[0]);
-            responseMessageTextView.setText(sourceStringArray[1]);
-            responseHeadersTextView.setText(sourceStringArray[2]);
-            responseBodyTextView.setText(sourceStringArray[3]);
-
-            // Hide the progress bar.
-            progressBar.setIndeterminate(false);
-            progressBar.setVisibility(View.GONE);
-
-            //Stop the swipe to refresh indicator if it is running
-            swipeRefreshLayout.setRefreshing(false);
-        });
-
-        // Create an error observer.
-        webViewSource.observeErrors().observe(this, errorString -> {
-            // Display an error snackbar if the string is not `""`.
-            if (!errorString.equals("")) {
-                Snackbar.make(swipeRefreshLayout, errorString, Snackbar.LENGTH_LONG).show();
-            }
-        });
-
-        // Implement swipe to refresh.
-        swipeRefreshLayout.setOnRefreshListener(() -> {
-            // Make the progress bar visible.
-            progressBar.setVisibility(View.VISIBLE);
-
-            // Set the progress bar to be indeterminate.
-            progressBar.setIndeterminate(true);
-
-            // Get the URL.
-            String urlString = urlEditText.getText().toString();
-
-            // Get the updated source.
-            webViewSource.updateSource(urlString);
-        });
-
-        // Set the go button on the keyboard to request new source data.
-        urlEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
-            // Request new source data if the enter key was pressed.
-            if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
-                // Hide the soft keyboard.
-                inputMethodManager.hideSoftInputFromWindow(urlEditText.getWindowToken(), 0);
-
-                // Remove the focus from the URL box.
-                urlEditText.clearFocus();
-
-                // Make the progress bar visible.
-                progressBar.setVisibility(View.VISIBLE);
-
-                // Set the progress bar to be indeterminate.
-                progressBar.setIndeterminate(true);
-
-                // Get the URL.
-                String urlString = urlEditText.getText().toString();
-
-                // Get the updated source.
-                webViewSource.updateSource(urlString);
-
-                // Consume the key press.
-                return true;
-            } else {
-                // Do not consume the key press.
-                return false;
-            }
-        });
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // Inflate the menu.  This adds items to the action bar if it is present.
-        getMenuInflater().inflate(R.menu.view_source_options_menu, menu);
-
-        // Display the menu.
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(@NonNull MenuItem menuItem) {
-        // Get a handle for the about alert dialog.
-        DialogFragment aboutDialogFragment = new AboutViewSourceDialog();
-
-        // Show the about alert dialog.
-        aboutDialogFragment.show(getSupportFragmentManager(), getString(R.string.about));
-
-        // Consume the event.
-        return true;
-    }
-
-    public void goBack(View view) {
-        // Go home.
-        NavUtils.navigateUpFromSameTask(activity);
-    }
-
-    private void highlightUrlText() {
-        // Get a handle for the URL EditText.
-        EditText urlEditText = findViewById(R.id.url_edittext);
-
-        // Get the URL string.
-        String urlString = urlEditText.getText().toString();
-
-        // Highlight the URL according to the protocol.
-        if (urlString.startsWith("file://")) {  // This is a file URL.
-            // De-emphasize only the protocol.
-            urlEditText.getText().setSpan(initialGrayColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-        } else if (urlString.startsWith("content://")) {
-            // De-emphasize only the protocol.
-            urlEditText.getText().setSpan(initialGrayColorSpan, 0, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-        } else {  // This is a web URL.
-            // Get the index of the `/` immediately after the domain name.
-            int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2));
-
-            // Create a base URL string.
-            String baseUrl;
-
-            // Get the base URL.
-            if (endOfDomainName > 0) {  // There is at least one character after the base URL.
-                // Get the base URL.
-                baseUrl = urlString.substring(0, endOfDomainName);
-            } else {  // There are no characters after the base URL.
-                // Set the base URL to be the entire URL string.
-                baseUrl = urlString;
-            }
-
-            // Get the index of the last `.` in the domain.
-            int lastDotIndex = baseUrl.lastIndexOf(".");
-
-            // Get the index of the penultimate `.` in the domain.
-            int penultimateDotIndex = baseUrl.lastIndexOf(".", lastDotIndex - 1);
-
-            // Markup the beginning of the URL.
-            if (urlString.startsWith("http://")) {  // Highlight the protocol of connections that are not encrypted.
-                urlEditText.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-
-                // De-emphasize subdomains.
-                if (penultimateDotIndex > 0) {  // There is more than one subdomain in the domain name.
-                    urlEditText.getText().setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-                }
-            } else if (urlString.startsWith("https://")) {  // De-emphasize the protocol of connections that are encrypted.
-                if (penultimateDotIndex > 0) {  // There is more than one subdomain in the domain name.
-                    // De-emphasize the protocol and the additional subdomains.
-                    urlEditText.getText().setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-                } else {  // There is only one subdomain in the domain name.
-                    // De-emphasize only the protocol.
-                    urlEditText.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-                }
-            }
-
-            // De-emphasize the text after the domain name.
-            if (endOfDomainName > 0) {
-                urlEditText.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-            }
-        }
-    }
-}
\ No newline at end of file