From 50cc3d99e4cbaa8052d4ff9a074ddf94205bc838 Mon Sep 17 00:00:00 2001 From: T0astBread Date: Fri, 6 Nov 2020 19:06:03 +0100 Subject: [PATCH 1/2] Suffix debug build IDs and version numbers to allow for parallel installation of debug and production builds --- app/build.gradle | 2 ++ app/src/main/AndroidManifest.xml | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) 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" /> From 1c1eaeb91e2a16aefcea85429263df2540a1083b Mon Sep 17 00:00:00 2001 From: T0astBread Date: Fri, 6 Nov 2020 19:13:45 +0100 Subject: [PATCH 2/2] Add proxy support This commit adds support for proxying network requests over a SOCKS or HTTP proxy and the corresponding preferences screen. A DelegatingProxy (which is a java.net.Proxy) is registered on every RestService. The DelegatingProxy delegates its proxying to a real Proxy created from the proxy preferences. This implementation is a bit ugly but the fact that RestServices are only created once while proxy preferences can change at any time made it hard to avoid global state and the DelegatingProxy class. Enabling proxying breaks search. --- .../hidroh/materialistic/DelegatingProxy.kt | 19 +++++++ .../hidroh/materialistic/Preferences.java | 27 ++++++++++ .../materialistic/PreferencesActivity.java | 6 +++ .../materialistic/SettingsActivity.java | 4 ++ .../hidroh/materialistic/ThemedActivity.java | 5 ++ .../data/RestServiceFactory.java | 7 ++- .../res/drawable/ic_baseline_language_24.xml | 9 ++++ app/src/main/res/layout/activity_settings.xml | 11 ++++ app/src/main/res/values/arrays.xml | 12 +++++ app/src/main/res/values/ids.xml | 1 + app/src/main/res/values/non_translatable.xml | 2 + app/src/main/res/values/preference_keys.xml | 5 ++ app/src/main/res/values/strings.xml | 9 ++++ app/src/main/res/xml/preferences_proxy.xml | 51 +++++++++++++++++++ 14 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/github/hidroh/materialistic/DelegatingProxy.kt create mode 100644 app/src/main/res/drawable/ic_baseline_language_24.xml create mode 100644 app/src/main/res/xml/preferences_proxy.xml 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 @@ + + + + + + + + + + + + + +