X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FViewSourceActivity.java;h=e4899ea329669f741c3b6355558b7e3f4bceba6e;hp=a0f51d14b7a2853f31fd5df68ab08d151f42079b;hb=b82022327701273b1b56419e8d6042895c0bc7b9;hpb=4d51aa9acb8daaec1326f14e5025fde6d1f0dcd8 diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java index a0f51d14..e4899ea3 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java @@ -23,10 +23,14 @@ 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; @@ -34,18 +38,27 @@ 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; // The AndroidX toolbar must be used until the minimum API is >= 21. +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.asynctasks.GetSource; 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()`. @@ -61,9 +74,8 @@ public class ViewSourceActivity extends AppCompatActivity { // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - // Get the screenshot and theme preferences. + // Get the screenshot preference. boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false); - boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false); // Disable screenshots if not allowed. if (!allowScreenshots) { @@ -71,11 +83,7 @@ public class ViewSourceActivity extends AppCompatActivity { } // Set the theme. - if (darkTheme) { - setTheme(R.style.PrivacyBrowserDark); - } else { - setTheme(R.style.PrivacyBrowserLight); - } + setTheme(R.style.PrivacyBrowser); // Run the default commands. super.onCreate(savedInstanceState); @@ -87,14 +95,19 @@ public class ViewSourceActivity extends AppCompatActivity { 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); - // The AndroidX toolbar must be used until the minimum API is >= 21. + // 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. @@ -107,17 +120,32 @@ public class ViewSourceActivity extends AppCompatActivity { actionBar.setCustomView(R.layout.view_source_app_bar); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); - // Get a handle for the url text box. + // 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 foreground color spans for highlighting the URLs. We have to use the deprecated `getColor()` until API >= 23. - redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700)); + // 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(); @@ -146,6 +174,146 @@ public class ViewSourceActivity extends AppCompatActivity { } }); + // 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. @@ -156,13 +324,17 @@ public class ViewSourceActivity extends AppCompatActivity { // 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 url = urlEditText.getText().toString(); + String urlString = urlEditText.getText().toString(); - // Get new source data for the current URL if it beings with `http`. - if (url.startsWith("http")) { - new GetSource(this, this, userAgent).execute(url); - } + // Get the updated source. + webViewSource.updateSource(urlString); // Consume the key press. return true; @@ -171,36 +343,6 @@ public class ViewSourceActivity extends AppCompatActivity { return false; } }); - - // Get a handle for the swipe refresh layout. - SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.view_source_swiperefreshlayout); - - // Implement swipe to refresh. - swipeRefreshLayout.setOnRefreshListener(() -> { - // Get the URL. - String url = urlEditText.getText().toString(); - - // Get new source data for the URL if it begins with `http`. - if (url.startsWith("http")) { - new GetSource(this, this, userAgent).execute(url); - } else { - // Stop the refresh animation. - swipeRefreshLayout.setRefreshing(false); - } - }); - - // Set the swipe to refresh color according to the theme. - if (darkTheme) { - swipeRefreshLayout.setColorSchemeResources(R.color.blue_600); - swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.gray_800); - } else { - swipeRefreshLayout.setColorSchemeResources(R.color.blue_700); - } - - // Get the source using an AsyncTask if the URL begins with `http`. - if ((currentUrl != null) && currentUrl.startsWith("http")) { - new GetSource(this, this, userAgent).execute(currentUrl); - } } @Override