public final static int DOMAINS_CUSTOM_USER_AGENT = 13;
// Start activity for result request codes. The public static entries are accessed from `OpenDialog()` and `SaveWebpageDialog()`.
- public static final int BROWSE_OPEN_REQUEST_CODE = 0;
- public static final int BROWSE_SAVE_WEBPAGE_REQUEST_CODE = 1;
+ public final static int BROWSE_OPEN_REQUEST_CODE = 0;
+ public final static int BROWSE_SAVE_WEBPAGE_REQUEST_CODE = 1;
private final int BROWSE_FILE_UPLOAD_REQUEST_CODE = 2;
+ // The proxy mode is public static so it can be accessed from `ProxyHelper()`.
+ // It is also used in `onRestart()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `applyAppSettings()`, and `applyProxy()`.
+ // It will be updated in `applyAppSettings()`, but it needs to be initialized here or the first run of `onPrepareOptionsMenu()` crashes.
+ public static String proxyMode = ProxyHelper.NONE;
+
// The permission result request codes are used in `onCreateContextMenu()`, `onCloseDownloadLocationPermissionDialog()`, `onRequestPermissionResult()`, `onSaveWebpage()`,
// `onCloseStoragePermissionDialog()`, and `initializeWebView()`.
// `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`.
private String webViewDefaultUserAgent;
- // The proxy mode is used in `onRestart()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `applyAppSettings()`, and `applyProxy()`.
- // It will be updated in `applyAppSettings()`, but it needs to be initialized here or the first run of `onPrepareOptionsMenu()` crashes.
- private String proxyMode = ProxyHelper.NONE;
-
// The incognito mode is set in `applyAppSettings()` and used in `initializeWebView()`.
private boolean incognitoModeEnabled;
switch (saveType) {
case StoragePermissionDialog.SAVE:
// Save the URL.
- new SaveUrl(this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
+ new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
break;
case StoragePermissionDialog.SAVE_AS_ARCHIVE:
switch (saveType) {
case StoragePermissionDialog.SAVE:
// Save the URL.
- new SaveUrl(this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
+ new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
break;
case StoragePermissionDialog.SAVE_AS_ARCHIVE:
// Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty.
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // The storage permission was granted.
// Save the raw URL.
- new SaveUrl(this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
+ new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
} else { // The storage permission was not granted.
// Display an error snackbar.
Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show();
/*
- * Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2017-2020 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
// Get new source data for the current URL if it beings with `http`.
if (url.startsWith("http")) {
- new GetSource(this, userAgent).execute(url);
+ new GetSource(this, this, userAgent).execute(url);
}
// Consume the key press.
// Get new source data for the URL if it begins with `http`.
if (url.startsWith("http")) {
- new GetSource(this, userAgent).execute(url);
+ new GetSource(this, this, userAgent).execute(url);
} else {
// Stop the refresh animation.
swipeRefreshLayout.setRefreshing(false);
// Get the source using an AsyncTask if the URL begins with `http`.
if ((currentUrl != null) && currentUrl.startsWith("http")) {
- new GetSource(this, userAgent).execute(currentUrl);
+ new GetSource(this, this, userAgent).execute(currentUrl);
}
}
package com.stoutner.privacybrowser.asynctasks;
import android.app.Activity;
+import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.AsyncTask;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.helpers.ProxyHelper;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
+import java.net.Proxy;
import java.net.URL;
import java.util.Locale;
// This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `SpannableStringBuilder[]` contains the results.
public class GetSource extends AsyncTask<String, Void, SpannableStringBuilder[]> {
- // Declare a weak reference to the calling activity.
+ // Define weak references to the calling context and activity.
+ private WeakReference<Context> contextWeakReference;
private WeakReference<Activity> activityWeakReference;
// Store the user agent.
private String userAgent;
- public GetSource(Activity activity, String userAgent) {
- // Populate the weak reference to the calling activity.
+ public GetSource(Context context, Activity activity, String userAgent) {
+ // Populate the weak references to the calling context and activity.
+ contextWeakReference = new WeakReference<>(context);
activityWeakReference = new WeakReference<>(activity);
// Store the user agent.
// `onPreExecute()` operates on the UI thread.
@Override
protected void onPreExecute() {
- // Get a handle for the activity.
- Activity viewSourceActivity = activityWeakReference.get();
+ // Get a handle for the calling activity.
+ Activity activity = activityWeakReference.get();
// Abort if the activity is gone.
- if ((viewSourceActivity == null) || viewSourceActivity.isFinishing()) {
+ if ((activity == null) || activity.isFinishing()) {
return;
}
// Get a handle for the progress bar.
- ProgressBar progressBar = viewSourceActivity.findViewById(R.id.progress_bar);
+ ProgressBar progressBar = activity.findViewById(R.id.progress_bar);
// Make the progress bar visible.
progressBar.setVisibility(View.VISIBLE);
SpannableStringBuilder responseHeadersBuilder = new SpannableStringBuilder();
SpannableStringBuilder responseBodyBuilder = new SpannableStringBuilder();
- // Get a handle for the activity.
+ // Get a handle for the context and activity.
+ Context context = contextWeakReference.get();
Activity activity = activityWeakReference.get();
// Abort if the activity is gone.
// Get the current URL from the main activity.
URL url = new URL(formattedUrlString[0]);
+ // Instantiate the proxy helper.
+ ProxyHelper proxyHelper = new ProxyHelper();
+
+ // Get the current proxy.
+ Proxy proxy = proxyHelper.getCurrentProxy(context);
+
// Open a connection to the URL. No data is actually sent at this point.
- HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
+ HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection(proxy);
// Define the variables necessary to build the request headers.
requestHeadersBuilder = new SpannableStringBuilder();
package com.stoutner.privacybrowser.asynctasks;
import android.app.Activity;
+import android.content.Context;
import android.os.AsyncTask;
import android.webkit.CookieManager;
import com.google.android.material.snackbar.Snackbar;
import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.helpers.ProxyHelper;
import com.stoutner.privacybrowser.views.NoSwipeViewPager;
import java.io.BufferedInputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
+import java.net.Proxy;
import java.net.URL;
public class SaveUrl extends AsyncTask<String, Void, String> {
- // Define a weak reference to the calling activity.
+ // Define a weak references for the calling context and activities.
+ private WeakReference<Context> contextWeakReference;
private WeakReference<Activity> activityWeakReference;
// Define a success string constant.
private Snackbar savingFileSnackbar;
// The public constructor.
- public SaveUrl(Activity activity, String filePathString, String userAgent, boolean cookiesEnabled) {
- // Populate the weak reference to the calling activity.
+ public SaveUrl(Context context, Activity activity, String filePathString, String userAgent, boolean cookiesEnabled) {
+ // Populate weak references to the calling context and activity.
+ contextWeakReference = new WeakReference<>(context);
activityWeakReference = new WeakReference<>(activity);
// Store the class variables.
@Override
protected String doInBackground(String... urlToSave) {
- // Get a handle for the activity.
+ // Get a handle for the context and activity.
+ Context context = contextWeakReference.get();
Activity activity = activityWeakReference.get();
// Abort if the activity is gone.
// Get the URL from the main activity.
URL url = new URL(urlToSave[0]);
+ // Instantiate the proxy helper.
+ ProxyHelper proxyHelper = new ProxyHelper();
+
+ // Get the current proxy.
+ Proxy proxy = proxyHelper.getCurrentProxy(context);
+
// Open a connection to the URL. No data is actually sent at this point.
- HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
+ HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection(proxy);
// Add the user agent to the header property.
httpUrlConnection.setRequestProperty("User-Agent", userAgent);
/*
- * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.net.Proxy;
import android.net.Uri;
import android.os.Build;
import android.os.Parcelable;
import android.util.ArrayMap;
-import android.util.Log;
import android.view.View;
import androidx.preference.PreferenceManager;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.SocketAddress;
import java.util.concurrent.Executor;
public class ProxyHelper {
Method onReceiveMethod = receiverClass.getDeclaredMethod("onReceive", Context.class, Intent.class);
// Create a proxy change intent.
- Intent proxyChangeIntent = new Intent(Proxy.PROXY_CHANGE_ACTION);
+ Intent proxyChangeIntent = new Intent(android.net.Proxy.PROXY_CHANGE_ACTION);
if (Build.VERSION.SDK_INT >= 21) {
// Get a proxy info class.
}
}
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) {
- Log.d("enableProxyThroughOrbot", "Exception: " + exception);
+ // Do nothing.
}
}
}
}
+
+ public Proxy getCurrentProxy(Context context) {
+ // Define a proxy variable.
+ Proxy proxy;
+
+ // Set the proxy according to the current proxy mode
+ switch (MainWebViewActivity.proxyMode) {
+ case (ProxyHelper.TOR):
+ if (Build.VERSION.SDK_INT >= 21) {
+ // Set the socket address to be localhost port 9050.
+ SocketAddress torSocketAddress = new InetSocketAddress("localhost", 9050);
+
+ // Set a SOCKS proxy.
+ proxy = new Proxy(Proxy.Type.SOCKS, torSocketAddress);
+ } else {
+ // Set the socket address to be localhost port 8118.
+ SocketAddress oldTorSocketAddress = new InetSocketAddress("localhost", 8118);
+
+ // Set an HTTP proxy.
+ proxy = new Proxy(Proxy.Type.HTTP, oldTorSocketAddress);
+ }
+ break;
+
+ case (ProxyHelper.I2P):
+ // Set the socket address to be localhost port 4444.
+ SocketAddress i2pSocketAddress = new InetSocketAddress("localhost", 4444);
+
+ // Set an HTTP proxy.
+ proxy = new Proxy(Proxy.Type.HTTP, i2pSocketAddress);
+ break;
+
+ case (ProxyHelper.CUSTOM):
+ // Get the shared preferences.
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ // Get the custom proxy URL string.
+ String customProxyUrlString = sharedPreferences.getString("proxy_custom_url", context.getString(R.string.proxy_custom_url_default_value));
+
+ // Parse the custom proxy URL.
+ try {
+ // Convert the custom proxy URL string to a URI.
+ Uri customProxyUri = Uri.parse(customProxyUrlString);
+
+ // Set the socket address.
+ SocketAddress customSocketAddress = new InetSocketAddress(customProxyUri.getHost(), customProxyUri.getPort());
+
+ // Get the custom proxy scheme.
+ String customProxyScheme = customProxyUri.getScheme();
+
+ // Set the proxy according to the scheme.
+ if ((customProxyScheme != null) && customProxyScheme.startsWith("socks")) { // A SOCKS proxy is specified.
+ // Set a SOCKS proxy.
+ proxy = new Proxy(Proxy.Type.SOCKS, customSocketAddress);
+ } else { // A SOCKS proxy is not specified.
+ // Set an HTTP proxy.
+ proxy = new Proxy(Proxy.Type.HTTP, customSocketAddress);
+ }
+ } catch (Exception exception) { // The custom proxy cannot be parsed.
+ // Disable the proxy.
+ proxy = Proxy.NO_PROXY;
+ }
+ break;
+
+ default: // No proxy is in use.
+ // Set a direct proxy.
+ proxy = Proxy.NO_PROXY;
+ break;
+
+ }
+
+ // Return the proxy.
+ return proxy;
+ }
}
\ No newline at end of file