diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
index 06d0529f..1bb2c57d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
@@ -137,8 +137,10 @@ public abstract class BaseActivity extends AppCompatActivity {
.registerTypeAdapter(Spanned.class, new SpannedTypeAdapter())
.create();
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+
OkHttpClient.Builder okBuilder =
- OkHttpUtils.getCompatibleClientBuilder()
+ OkHttpUtils.getCompatibleClientBuilder(preferences)
.addInterceptor(new AuthInterceptor(this))
.dispatcher(mastodonApiDispatcher);
diff --git a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java
index 0c8c0a52..4449fc46 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.java
@@ -152,7 +152,7 @@ public class LoginActivity extends AppCompatActivity {
private MastodonApi getApiFor(String domain) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + domain)
- .client(OkHttpUtils.getCompatibleClient())
+ .client(OkHttpUtils.getCompatibleClient(preferences))
.addConverterFactory(GsonConverterFactory.create())
.build();
diff --git a/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java b/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java
index 4fe10bc8..3b35255d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java
+++ b/app/src/main/java/com/keylesspalace/tusky/NotificationPullJobCreator.java
@@ -76,8 +76,10 @@ public final class NotificationPullJobCreator implements JobCreator {
}
private static MastodonApi createMastodonApi(String domain, Context context) {
+ SharedPreferences preferences = context.getSharedPreferences(
+ context.getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
- OkHttpClient okHttpClient = OkHttpUtils.getCompatibleClientBuilder()
+ OkHttpClient okHttpClient = OkHttpUtils.getCompatibleClientBuilder(preferences)
.addInterceptor(new AuthInterceptor(context))
.build();
diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
index fee6dc8b..abcaecad 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
+++ b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
@@ -17,6 +17,8 @@ package com.keylesspalace.tusky;
import android.app.Application;
import android.arch.persistence.room.Room;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatDelegate;
import com.evernote.android.job.JobManager;
@@ -37,7 +39,8 @@ public class TuskyApplication extends Application {
super.onCreate();
// Initialize Picasso configuration
Picasso.Builder builder = new Picasso.Builder(this);
- builder.downloader(new OkHttp3Downloader(OkHttpUtils.getCompatibleClient()));
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ builder.downloader(new OkHttp3Downloader(OkHttpUtils.getCompatibleClient(preferences)));
if (BuildConfig.DEBUG) {
builder.listener((picasso, uri, exception) -> exception.printStackTrace());
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java
index 9e96d5ac..7fab0c39 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/PreferencesFragment.java
@@ -16,8 +16,10 @@
package com.keylesspalace.tusky.fragment;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
+import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.support.annotation.XmlRes;
@@ -27,7 +29,10 @@ import com.keylesspalace.tusky.PreferencesActivity;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.util.NotificationManager;
-public class PreferencesFragment extends PreferenceFragment {
+public class PreferencesFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
+ SharedPreferences sharedPreferences;
+ static boolean httpProxyChanged = false;
+ static boolean pendingRestart = false;
public static PreferencesFragment newInstance(@XmlRes int preference) {
PreferencesFragment fragment = new PreferencesFragment();
@@ -101,6 +106,91 @@ public class PreferencesFragment extends PreferenceFragment {
});
}
+ Preference httpProxyPreferences = findPreference("httpProxyPreferences");
+ if(httpProxyPreferences != null) {
+ httpProxyPreferences.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ PreferencesActivity activity = (PreferencesActivity) getActivity();
+ if (activity != null) {
+ pendingRestart = false;
+ activity.showFragment(R.xml.http_proxy_preferences, R.string.pref_title_http_proxy_settings);
+ }
+
+ return true;
+ }
+ });
+ }
+
}
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ sharedPreferences = getPreferenceManager().getSharedPreferences();
+ sharedPreferences.registerOnSharedPreferenceChangeListener(this);
+
+ updateSummary("httpProxyServer");
+ updateSummary("httpProxyPort");
+ updateHttpProxySummary();
+ }
+
+ @Override
+ public void onPause() {
+ sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
+ super.onPause();
+ if (pendingRestart) {
+ pendingRestart = false;
+ httpProxyChanged = false;
+ System.exit(0);
+ }
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ switch (key) {
+ case "httpProxyServer":
+ case "httpProxyPort":
+ updateSummary(key);
+ case "httpProxyEnabled":
+ httpProxyChanged = true;
+ break;
+ default:
+ }
+ }
+
+ private void updateSummary(String key) {
+ switch (key) {
+ case "httpProxyServer":
+ case "httpProxyPort":
+ EditTextPreference editTextPreference = (EditTextPreference) findPreference(key);
+ if (editTextPreference != null) {
+ editTextPreference.setSummary(editTextPreference.getText());
+ }
+ break;
+ default:
+ }
+ }
+
+ private void updateHttpProxySummary() {
+ Preference httpProxyPref = findPreference("httpProxyPreferences");
+ if (httpProxyPref != null) {
+ if (httpProxyChanged) {
+ pendingRestart = true;
+ }
+
+ Boolean httpProxyEnabled = sharedPreferences.getBoolean("httpProxyEnabled", false);
+
+ String httpServer = sharedPreferences.getString("httpProxyServer", "");
+ int httpPort = Integer.parseInt(sharedPreferences.getString("httpProxyPort", "-1"));
+
+ if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0 && httpPort < 65535)) {
+ httpProxyPref.setSummary(httpServer + ":" + httpPort);
+ } else {
+ httpProxyPref.setSummary("");
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
index 9f4fb436..0873b218 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
@@ -15,7 +15,9 @@
package com.keylesspalace.tusky.util;
+import android.content.SharedPreferences;
import android.os.Build;
+import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.util.Log;
@@ -23,6 +25,8 @@ import com.keylesspalace.tusky.BuildConfig;
import java.io.IOException;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
@@ -62,7 +66,11 @@ public class OkHttpUtils {
* TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20.
*/
@NonNull
- public static OkHttpClient.Builder getCompatibleClientBuilder() {
+ public static OkHttpClient.Builder getCompatibleClientBuilder(SharedPreferences preferences) {
+ boolean httpProxyEnabled = preferences.getBoolean("httpProxyEnabled", false);
+ String httpServer = preferences.getString("httpProxyServer", "");
+ int httpPort = Integer.parseInt(preferences.getString("httpProxyPort", "-1"));
+
ConnectionSpec fallback = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.allEnabledCipherSuites()
.supportsTlsExtensions(true)
@@ -80,12 +88,17 @@ public class OkHttpUtils {
.writeTimeout(30, TimeUnit.SECONDS)
.connectionSpecs(specList);
+ if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) {
+ InetSocketAddress address = InetSocketAddress.createUnresolved(httpServer, httpPort);
+ builder.proxy(new Proxy(Proxy.Type.HTTP, address));
+ }
+
return enableHigherTlsOnPreLollipop(builder);
}
@NonNull
- public static OkHttpClient getCompatibleClient() {
- return getCompatibleClientBuilder().build();
+ public static OkHttpClient getCompatibleClient(SharedPreferences preferences) {
+ return getCompatibleClientBuilder(preferences).build();
}
/**
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d90719fc..b2c20f6d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -177,6 +177,11 @@
Show boosts
Show replies
Show media previews
+ Proxy
+ HTTP proxy
+ Enable HTTP proxy
+ HTTP proxy server
+ HTTP proxy port
- 15 minutes
diff --git a/app/src/main/res/xml/http_proxy_preferences.xml b/app/src/main/res/xml/http_proxy_preferences.xml
new file mode 100644
index 00000000..05183535
--- /dev/null
+++ b/app/src/main/res/xml/http_proxy_preferences.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index d9429214..d005a25c 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -74,4 +74,12 @@
android:title="@string/pref_title_edit_notification_settings" />
+
+
+
+
+