diff --git a/app/build.gradle b/app/build.gradle index 4c091e12e..72fe3b5bf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,8 @@ android { buildTypes { debug { + applicationIdSuffix ".debug" + versionNameSuffix "-debug" minifyEnabled !rootProject.ext.ci useProguard false } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3fa857c33..4d8a6aecb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,12 +27,12 @@ - - - - + + @@ -271,15 +271,15 @@ android:name=".data.WebCacheService" android:exported="false" /> diff --git a/app/src/main/java/io/github/hidroh/materialistic/DelegatingProxy.kt b/app/src/main/java/io/github/hidroh/materialistic/DelegatingProxy.kt new file mode 100644 index 000000000..84220af20 --- /dev/null +++ b/app/src/main/java/io/github/hidroh/materialistic/DelegatingProxy.kt @@ -0,0 +1,19 @@ +package io.github.hidroh.materialistic + +import android.content.Context +import java.net.InetSocketAddress +import java.net.Proxy + +class DelegatingProxy : Proxy(Type.SOCKS, InetSocketAddress.createUnresolved("127.0.0.1", 1)) { + override fun type() = activeProxy.type() + override fun address() = activeProxy.address() + + companion object { + var activeProxy: Proxy = NO_PROXY + + @JvmStatic + fun updateFromPreferences(context: Context) { + activeProxy = Preferences.getProxy(context) + } + } +} diff --git a/app/src/main/java/io/github/hidroh/materialistic/Preferences.java b/app/src/main/java/io/github/hidroh/materialistic/Preferences.java index 666e32d98..80ef1349d 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/Preferences.java +++ b/app/src/main/java/io/github/hidroh/materialistic/Preferences.java @@ -23,6 +23,7 @@ import android.content.pm.PackageManager; import android.text.TextUtils; +import java.net.*; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; @@ -304,6 +305,21 @@ public static SwipeAction[] getListSwipePreferences(Context context) { return new SwipeAction[]{parseSwipeAction(left), parseSwipeAction(right)}; } + public static Proxy getProxy(Context context) { + boolean isEnabled = get(context, R.string.pref_proxy_enabled, false); + if (!isEnabled) + return Proxy.NO_PROXY; + Proxy.Type type = getProxyType(context); + String host = get(context, R.string.pref_proxy_host, R.string.pref_proxy_host_default); + int port = Integer.parseInt(get(context, R.string.pref_proxy_port, R.string.pref_proxy_port_default)); + try { + return new Proxy(type, new InetSocketAddress(InetAddress.getByName(host), port)); + } catch (UnknownHostException e) { + e.printStackTrace(); + return Proxy.NO_PROXY; + } + } + public static void reset(Context context) { PreferenceManager.getDefaultSharedPreferences(context) .edit() @@ -311,6 +327,17 @@ public static void reset(Context context) { .apply(); } + private static Proxy.Type getProxyType(Context context) { + String protocolStr = get(context, R.string.pref_proxy_protocol, R.string.pref_proxy_protocol_socks); + if (context.getResources().getString(R.string.pref_proxy_protocol_value_socks).equals(protocolStr)) { + return Proxy.Type.SOCKS; + } else if (context.getResources().getString(R.string.pref_proxy_protocol_value_http).equals(protocolStr)) { + return Proxy.Type.HTTP; + } else { + throw new IllegalArgumentException("Invalid proxy protocol: " + protocolStr); + } + } + private static SwipeAction parseSwipeAction(String value) { try { return SwipeAction.valueOf(value); diff --git a/app/src/main/java/io/github/hidroh/materialistic/PreferencesActivity.java b/app/src/main/java/io/github/hidroh/materialistic/PreferencesActivity.java index 058cc8370..898e4844e 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/PreferencesActivity.java +++ b/app/src/main/java/io/github/hidroh/materialistic/PreferencesActivity.java @@ -48,6 +48,12 @@ protected void onCreate(Bundle savedInstanceState) { } } + @Override + protected void onDestroy() { + super.onDestroy(); + DelegatingProxy.updateFromPreferences(this); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { diff --git a/app/src/main/java/io/github/hidroh/materialistic/SettingsActivity.java b/app/src/main/java/io/github/hidroh/materialistic/SettingsActivity.java index aa814f859..e7e00879b 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/SettingsActivity.java +++ b/app/src/main/java/io/github/hidroh/materialistic/SettingsActivity.java @@ -59,6 +59,10 @@ protected void onCreate(Bundle savedInstanceState) { startActivity(new Intent(SettingsActivity.this, PreferencesActivity.class) .putExtra(PreferencesActivity.EXTRA_TITLE, R.string.readability) .putExtra(PreferencesActivity.EXTRA_PREFERENCES, R.xml.preferences_readability))); + findViewById(R.id.menu_proxy).setOnClickListener(v -> + startActivity(new Intent(SettingsActivity.this, PreferencesActivity.class) + .putExtra(PreferencesActivity.EXTRA_TITLE, R.string.proxy) + .putExtra(PreferencesActivity.EXTRA_PREFERENCES, R.xml.preferences_proxy))); findViewById(R.id.drawer_about).setOnClickListener(v -> startActivity(new Intent(SettingsActivity.this, AboutActivity.class))); findViewById(R.id.drawer_release).setOnClickListener(v -> diff --git a/app/src/main/java/io/github/hidroh/materialistic/ThemedActivity.java b/app/src/main/java/io/github/hidroh/materialistic/ThemedActivity.java index d70ae2bc7..e2d70c071 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/ThemedActivity.java +++ b/app/src/main/java/io/github/hidroh/materialistic/ThemedActivity.java @@ -40,6 +40,11 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTaskTitle(getTitle()); mMenuTintDelegate.onActivityCreated(this); + + // Maybe not the right place to do this but this needs to run + // after the app starts and ThemedActivity is a common base + // class for activities + DelegatingProxy.updateFromPreferences(this); } @Override diff --git a/app/src/main/java/io/github/hidroh/materialistic/data/RestServiceFactory.java b/app/src/main/java/io/github/hidroh/materialistic/data/RestServiceFactory.java index 3f8340ad0..6d2c97171 100644 --- a/app/src/main/java/io/github/hidroh/materialistic/data/RestServiceFactory.java +++ b/app/src/main/java/io/github/hidroh/materialistic/data/RestServiceFactory.java @@ -24,7 +24,8 @@ import javax.inject.Inject; -import okhttp3.Call; +import io.github.hidroh.materialistic.*; +import okhttp3.*; import retrofit2.Retrofit; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; @@ -72,6 +73,10 @@ public T create(String baseUrl, Class clazz, Executor callbackExecutor) { builder.callFactory(mCallFactory) .callbackExecutor(callbackExecutor != null ? callbackExecutor : new MainThreadExecutor()); + OkHttpClient httpClient = new OkHttpClient.Builder() + .proxy(new DelegatingProxy()) + .build(); + builder.client(httpClient); return builder.baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build() diff --git a/app/src/main/res/drawable/ic_baseline_language_24.xml b/app/src/main/res/drawable/ic_baseline_language_24.xml new file mode 100644 index 000000000..c70400f8e --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_language_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 3239813ea..d9f873420 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -90,6 +90,17 @@ android:layout_width="match_parent" android:layout_height="@dimen/divider" /> + + + + article readability + + + @string/pref_proxy_protocol_socks + @string/pref_proxy_protocol_http + + + @string/pref_proxy_protocol_value_socks + @string/pref_proxy_protocol_value_http + + socks + http + @string/comment_max_lines_3 diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index 75d0cc82e..cab92b814 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -63,6 +63,7 @@ + diff --git a/app/src/main/res/values/non_translatable.xml b/app/src/main/res/values/non_translatable.xml index d1eed3ad7..8512b766f 100644 --- a/app/src/main/res/values/non_translatable.xml +++ b/app/src/main/res/values/non_translatable.xml @@ -95,5 +95,7 @@ ]]> io.github.hidroh.materialistic.FabAwareScrollBehavior + 127.0.0.1 + 9050 diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 62db43f68..82a6e1d69 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -66,4 +66,9 @@ pref_username pref_volume pref_volume_help + pref_proxy + pref_proxy_enabled + pref_proxy_protocol + pref_proxy_host + pref_proxy_port \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 33b07e4c5..c3b790372 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,6 +23,7 @@ Best Stories Comments What\'s New + Proxy Materialistic Open drawer Close drawer @@ -110,6 +111,13 @@ Disable to improve scroll accuracy Swipe left to Swipe right to + Use proxy + Use a proxy server for all network requests not made via an external browser + Proxy protocol + SOCKS + HTTP + Proxy server host + Proxy server port Unable to connect to Hacker News. Check your connection or try again. Select a story to view @@ -321,5 +329,6 @@ Share file Privacy Policy Downloads + Proxy diff --git a/app/src/main/res/xml/preferences_proxy.xml b/app/src/main/res/xml/preferences_proxy.xml new file mode 100644 index 000000000..20bd927ae --- /dev/null +++ b/app/src/main/res/xml/preferences_proxy.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + +