From 48a5619c90055274285ce2207e23aa5c8bc6e433 Mon Sep 17 00:00:00 2001 From: werman Date: Sun, 24 Jun 2018 22:59:24 +0300 Subject: [PATCH 1/2] Add support for proxies. Supported proxies are: HTTP and SOCKS5. SOCKS4 proxies aren't supported because OkHttp doesn't support them because Android has issues with SOCKS4. All http requests now made through OkHttp. All OkHttp instances now share same thread pool. --- .../ActivityRadioStationDetail.java | 19 +- .../radiodroid2/AlarmReceiver.java | 7 +- .../radiodroid2/FragmentBase.java | 8 +- .../radiodroid2/FragmentHistory.java | 3 +- .../radiodroid2/FragmentPlayer.java | 6 +- .../radiodroid2/FragmentServerInfo.java | 8 +- .../radiodroid2/FragmentSettings.java | 12 + .../radiodroid2/FragmentStarred.java | 4 +- .../radiodroid2/FragmentStations.java | 4 +- .../radiodroid2/RadioDroidApp.java | 65 +++++ .../radiodroid2/StationSaveManager.java | 12 +- .../programmierecke/radiodroid2/Utils.java | 125 ++++++---- .../adapters/ItemAdapterStation.java | 19 +- .../radiodroid2/players/RadioPlayer.java | 10 +- .../radiodroid2/proxy/ProxySettings.java | 30 +++ .../proxy/ProxySettingsDialog.java | 223 ++++++++++++++++++ .../main/res/layout/dialog_proxy_settings.xml | 54 +++++ .../main/res/layout/layout_server_alert.xml | 4 +- app/src/main/res/values-el/strings.xml | 4 +- app/src/main/res/values-es/strings.xml | 4 +- app/src/main/res/values-ru/strings.xml | 4 +- app/src/main/res/values-sk/strings.xml | 4 +- app/src/main/res/values-tr/strings.xml | 4 +- app/src/main/res/values-zh-rCN/strings.xml | 4 +- app/src/main/res/values/strings.xml | 11 +- app/src/main/res/xml/preferences.xml | 3 + 26 files changed, 561 insertions(+), 90 deletions(-) create mode 100644 app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettings.java create mode 100644 app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettingsDialog.java create mode 100644 app/src/main/res/layout/dialog_proxy_settings.xml diff --git a/app/src/main/java/net/programmierecke/radiodroid2/ActivityRadioStationDetail.java b/app/src/main/java/net/programmierecke/radiodroid2/ActivityRadioStationDetail.java index 438735cce..6e25e448f 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/ActivityRadioStationDetail.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/ActivityRadioStationDetail.java @@ -20,6 +20,8 @@ import net.programmierecke.radiodroid2.data.DataRadioStation; +import okhttp3.OkHttpClient; + public class ActivityRadioStationDetail extends AppCompatActivity implements TimePickerDialog.OnTimeSetListener { private DataRadioStation itsStation; private MenuItem m_Menu_Star; @@ -48,10 +50,13 @@ protected void onCreate(Bundle savedInstanceState) { UpdateMenu(); getApplicationContext().sendBroadcast(new Intent(ActivityMain.ACTION_SHOW_LOADING)); + + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + new AsyncTask() { @Override protected String doInBackground(Void... params) { - return Utils.downloadFeed(getApplicationContext(), RadioBrowserServerManager.getWebserviceEndpoint(getApplicationContext(), String.format(Locale.US, "json/stations/byid/%s", aStationID)),true,null); + return Utils.downloadFeed(httpClient, getApplicationContext(), RadioBrowserServerManager.getWebserviceEndpoint(getApplicationContext(), String.format(Locale.US, "json/stations/byid/%s", aStationID)),true,null); } @Override @@ -100,13 +105,17 @@ public boolean onCreateOptionsMenu(Menu menu) { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.action_play: - Utils.Play(itsStation,this,false); + case R.id.action_play: { + RadioDroidApp radioDroidApp = (RadioDroidApp) getApplication(); + Utils.Play(radioDroidApp.getHttpClient(), itsStation, this, false); return true; + } - case R.id.action_share: - Utils.Play(itsStation,this,true); + case R.id.action_share: { + RadioDroidApp radioDroidApp = (RadioDroidApp) getApplication(); + Utils.Play(radioDroidApp.getHttpClient(), itsStation, this, true); return true; + } case R.id.action_star: Star(); diff --git a/app/src/main/java/net/programmierecke/radiodroid2/AlarmReceiver.java b/app/src/main/java/net/programmierecke/radiodroid2/AlarmReceiver.java index d3d6d94a1..e634e68ac 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/AlarmReceiver.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/AlarmReceiver.java @@ -19,6 +19,8 @@ import net.programmierecke.radiodroid2.data.DataRadioStation; +import okhttp3.OkHttpClient; + public class AlarmReceiver extends BroadcastReceiver { String url; int alarmId; @@ -118,12 +120,15 @@ public void onServiceDisconnected(ComponentName className) { int timeout = 10; private void Play(final Context context, final String stationId) { + RadioDroidApp radioDroidApp = (RadioDroidApp) context.getApplicationContext(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + new AsyncTask() { @Override protected String doInBackground(Void... params) { String result = null; for (int i=0;i<20;i++){ - result = Utils.getRealStationLink(context, stationId); + result = Utils.getRealStationLink(httpClient, context, stationId); if (result != null){ return result; } diff --git a/app/src/main/java/net/programmierecke/radiodroid2/FragmentBase.java b/app/src/main/java/net/programmierecke/radiodroid2/FragmentBase.java index 92e268c2b..f64cdeb1b 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/FragmentBase.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/FragmentBase.java @@ -13,6 +13,8 @@ import java.util.HashMap; +import okhttp3.OkHttpClient; + public class FragmentBase extends Fragment { private static final String TAG = "FragmentBase"; @@ -77,6 +79,10 @@ public void DownloadUrl(final boolean forceUpdate, final boolean displayProgress if (getContext() != null && displayProgress) { getContext().sendBroadcast(new Intent(ActivityMain.ACTION_SHOW_LOADING)); } + + RadioDroidApp radioDroidApp = (RadioDroidApp) getActivity().getApplication(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + new AsyncTask() { @Override protected String doInBackground(Void... params) { @@ -84,7 +90,7 @@ protected String doInBackground(Void... params) { if (!show_broken) { p.put("hidebroken", "true"); } - return Utils.downloadFeed(getActivity(), url, forceUpdate, p); + return Utils.downloadFeed(httpClient, getActivity(), url, forceUpdate, p); } @Override diff --git a/app/src/main/java/net/programmierecke/radiodroid2/FragmentHistory.java b/app/src/main/java/net/programmierecke/radiodroid2/FragmentHistory.java index aaef332a0..00912072e 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/FragmentHistory.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/FragmentHistory.java @@ -30,7 +30,8 @@ public class FragmentHistory extends Fragment { void onStationClick(DataRadioStation theStation) { Context context = getContext(); - Utils.Play(theStation, context); + RadioDroidApp radioDroidApp = (RadioDroidApp) getActivity().getApplication(); + Utils.Play(radioDroidApp.getHttpClient(), theStation, context); historyManager.add(theStation); diff --git a/app/src/main/java/net/programmierecke/radiodroid2/FragmentPlayer.java b/app/src/main/java/net/programmierecke/radiodroid2/FragmentPlayer.java index d42602870..ef2e4228c 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/FragmentPlayer.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/FragmentPlayer.java @@ -192,9 +192,9 @@ private void SetInfoFromHistory(boolean startPlaying) { if(history.length > 0) { DataRadioStation lastStation = history[0]; - if(startPlaying) - Utils.Play(lastStation, getContext()); - else { + if(startPlaying) { + Utils.Play(radioDroidApp.getHttpClient(),lastStation, getContext()); + } else { aTextViewName.setText(lastStation.Name); if (!Utils.shouldLoadIcons(getContext())) diff --git a/app/src/main/java/net/programmierecke/radiodroid2/FragmentServerInfo.java b/app/src/main/java/net/programmierecke/radiodroid2/FragmentServerInfo.java index 9dc440df3..2b1778fca 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/FragmentServerInfo.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/FragmentServerInfo.java @@ -16,6 +16,8 @@ import net.programmierecke.radiodroid2.data.DataStatistics; import net.programmierecke.radiodroid2.interfaces.IFragmentRefreshable; +import okhttp3.OkHttpClient; + public class FragmentServerInfo extends Fragment implements IFragmentRefreshable { private ItemAdapterStatistics itemAdapterStatistics; @@ -38,12 +40,16 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa void Download(final boolean forceUpdate){ getContext().sendBroadcast(new Intent(ActivityMain.ACTION_SHOW_LOADING)); + + RadioDroidApp radioDroidApp = (RadioDroidApp) getActivity().getApplication(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + new AsyncTask() { @Override protected String doInBackground(Void... params) { String endpoint = RadioBrowserServerManager.getWebserviceEndpoint(getActivity(),"json/stats"); if (endpoint != null) { - return Utils.downloadFeed(getActivity(), endpoint, forceUpdate, null); + return Utils.downloadFeed(httpClient, getActivity(), endpoint, forceUpdate, null); } return null; } diff --git a/app/src/main/java/net/programmierecke/radiodroid2/FragmentSettings.java b/app/src/main/java/net/programmierecke/radiodroid2/FragmentSettings.java index 8f312de1e..43a931639 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/FragmentSettings.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/FragmentSettings.java @@ -24,6 +24,7 @@ import net.programmierecke.radiodroid2.data.MPDServer; import net.programmierecke.radiodroid2.interfaces.IApplicationSelected; +import net.programmierecke.radiodroid2.proxy.ProxySettingsDialog; import java.lang.ref.WeakReference; import java.net.InetAddress; @@ -66,6 +67,17 @@ public boolean onPreferenceClick(Preference preference) { return false; } }); + + findPreference("settings_proxy").setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + ProxySettingsDialog proxySettingsDialog = new ProxySettingsDialog(); + proxySettingsDialog.setCancelable(true); + proxySettingsDialog.show(getFragmentManager(), ""); + return false; + } + }); + findPreference("mpd_servers_viewer").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { diff --git a/app/src/main/java/net/programmierecke/radiodroid2/FragmentStarred.java b/app/src/main/java/net/programmierecke/radiodroid2/FragmentStarred.java index 41e3503bb..b6a83d430 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/FragmentStarred.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/FragmentStarred.java @@ -26,7 +26,9 @@ public class FragmentStarred extends Fragment implements IAdapterRefreshable, IC private HistoryManager historyManager; void onStationClick(DataRadioStation theStation) { - Utils.Play(theStation, getContext()); + RadioDroidApp radioDroidApp = (RadioDroidApp) getActivity().getApplication(); + + Utils.Play(radioDroidApp.getHttpClient(), theStation, getContext()); historyManager.add(theStation); } diff --git a/app/src/main/java/net/programmierecke/radiodroid2/FragmentStations.java b/app/src/main/java/net/programmierecke/radiodroid2/FragmentStations.java index 27b02ae85..1b58d8234 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/FragmentStations.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/FragmentStations.java @@ -31,7 +31,9 @@ public class FragmentStations extends FragmentBase { void onStationClick(DataRadioStation theStation) { Context context = getContext(); - Utils.Play(theStation, context); + + RadioDroidApp radioDroidApp = (RadioDroidApp) getActivity().getApplication(); + Utils.Play(radioDroidApp.getHttpClient(), theStation, context); historyManager.add(theStation); diff --git a/app/src/main/java/net/programmierecke/radiodroid2/RadioDroidApp.java b/app/src/main/java/net/programmierecke/radiodroid2/RadioDroidApp.java index d6d680cda..d13e108d2 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/RadioDroidApp.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/RadioDroidApp.java @@ -1,25 +1,63 @@ package net.programmierecke.radiodroid2; import android.app.Application; +import android.content.SharedPreferences; +import android.support.annotation.NonNull; import android.support.v7.app.AppCompatDelegate; +import android.support.v7.preference.PreferenceManager; import com.jakewharton.picasso.OkHttp3Downloader; import com.squareup.picasso.Picasso; +import net.programmierecke.radiodroid2.proxy.ProxySettings; import net.programmierecke.radiodroid2.recording.RecordingsManager; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import okhttp3.ConnectionPool; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + public class RadioDroidApp extends Application { private HistoryManager historyManager; private FavouriteManager favouriteManager; private RecordingsManager recordingsManager; + private ConnectionPool connectionPool; + private OkHttpClient httpClient; + + public class UserAgentInterceptor implements Interceptor { + + private final String userAgent; + + public UserAgentInterceptor(String userAgent) { + this.userAgent = userAgent; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request originalRequest = chain.request(); + Request requestWithUserAgent = originalRequest.newBuilder() + .header("User-Agent", userAgent) + .build(); + return chain.proceed(requestWithUserAgent); + } + } + @Override public void onCreate() { super.onCreate(); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); + connectionPool = new ConnectionPool(); + + rebuildHttpClient(); + Picasso.Builder builder = new Picasso.Builder(this); builder.downloader(new OkHttp3Downloader(this, Integer.MAX_VALUE)); Picasso picassoInstance = builder.build(); @@ -33,6 +71,15 @@ public void onCreate() { recordingsManager = new RecordingsManager(); } + public void rebuildHttpClient() { + httpClient = newHttpClient() + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .addInterceptor(new UserAgentInterceptor("RadioDroid2/" + BuildConfig.VERSION_NAME)) + .build(); + } + public HistoryManager getHistoryManager() { return historyManager; } @@ -44,4 +91,22 @@ public FavouriteManager getFavouriteManager() { public RecordingsManager getRecordingsManager() { return recordingsManager; } + + public OkHttpClient getHttpClient() { + return httpClient; + } + + public OkHttpClient.Builder newHttpClient() { + OkHttpClient.Builder builder = new OkHttpClient.Builder().connectionPool(connectionPool); + setCurrentOkHttpProxy(builder); + return builder; + } + + public void setCurrentOkHttpProxy(@NonNull OkHttpClient.Builder builder) { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); + ProxySettings proxySettings = ProxySettings.fromPreferences(sharedPref); + if (proxySettings != null) { + Utils.setOkHttpProxy(builder, proxySettings); + } + } } diff --git a/app/src/main/java/net/programmierecke/radiodroid2/StationSaveManager.java b/app/src/main/java/net/programmierecke/radiodroid2/StationSaveManager.java index a4d409278..2e2b5997a 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/StationSaveManager.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/StationSaveManager.java @@ -29,6 +29,8 @@ import java.util.List; import java.util.Vector; +import okhttp3.OkHttpClient; + public class StationSaveManager { Context context; List listStations = new ArrayList(); @@ -206,6 +208,9 @@ protected void onPostExecute(DataRadioStation[] result) { protected final String M3U_PREFIX = "#RADIOBROWSERUUID:"; boolean SaveM3UInternal(String filePath, String fileName){ + final RadioDroidApp radioDroidApp = (RadioDroidApp) context.getApplicationContext(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + try { File f = new File(filePath, fileName); BufferedWriter bw = new BufferedWriter(new FileWriter(f, false)); @@ -213,7 +218,7 @@ boolean SaveM3UInternal(String filePath, String fileName){ for (DataRadioStation station : listStations) { String result = null; for (int i=0;i<20;i++){ - result = Utils.getRealStationLink(context, station.ID); + result = Utils.getRealStationLink(httpClient, context, station.ID); if (result != null){ break; } @@ -256,11 +261,14 @@ DataRadioStation[] LoadM3UInternal(String filePath, String fileName){ BufferedReader br = new BufferedReader(new FileReader(f)); String line; + final RadioDroidApp radioDroidApp = (RadioDroidApp) context.getApplicationContext(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + while ((line = br.readLine()) != null) { if (line.startsWith(M3U_PREFIX)){ try { String uuid = line.substring(M3U_PREFIX.length()).trim(); - DataRadioStation station = Utils.getStationByUuid(context, uuid); + DataRadioStation station = Utils.getStationByUuid(httpClient, context, uuid); if (station != null) { loadedItems.add(station); } diff --git a/app/src/main/java/net/programmierecke/radiodroid2/Utils.java b/app/src/main/java/net/programmierecke/radiodroid2/Utils.java index a9086c3e1..054d2b728 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/Utils.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/Utils.java @@ -15,9 +15,11 @@ import android.net.NetworkInfo; import android.net.Uri; import android.os.AsyncTask; +import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.preference.PreferenceManager; +import android.text.TextUtils; import android.util.Log; import android.widget.Toast; @@ -26,24 +28,35 @@ import net.programmierecke.radiodroid2.data.DataRadioStation; import net.programmierecke.radiodroid2.data.MPDServer; +import net.programmierecke.radiodroid2.proxy.ProxySettings; + import org.json.JSONObject; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.InputStream; +import java.io.IOException; import java.io.InputStreamReader; -import java.io.OutputStreamWriter; import java.lang.reflect.Type; -import java.net.HttpURLConnection; -import java.net.URL; +import java.net.InetSocketAddress; +import java.net.Proxy; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; +import okhttp3.Authenticator; +import okhttp3.Credentials; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.Route; + public class Utils { private static int loadIcons = -1; @@ -101,7 +114,7 @@ public static void writeFileCache(Context ctx, String theURI, String content){ } } - public static String downloadFeed(Context ctx, String theURI, boolean forceUpdate, Map dictParams) { + public static String downloadFeed(OkHttpClient httpClient, Context ctx, String theURI, boolean forceUpdate, Map dictParams) { if (!forceUpdate) { String cache = getCacheFile(ctx, theURI); if (cache != null) { @@ -109,46 +122,31 @@ public static String downloadFeed(Context ctx, String theURI, boolean forceUpdat } } - StringBuilder chaine = new StringBuilder(""); try{ - URL url = new URL(theURI); - HttpURLConnection connection = (HttpURLConnection)url.openConnection(); - connection.setConnectTimeout(4000); - connection.setReadTimeout(3000); - connection.setRequestProperty("User-Agent", "RadioDroid2/"+BuildConfig.VERSION_NAME); - connection.setDoInput(true); - if (dictParams != null) { - connection.setDoOutput(true); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("Accept", "application/json"); - connection.setRequestMethod("POST"); - } else { - connection.setRequestMethod("GET"); - } - connection.connect(); + HttpUrl url = HttpUrl.parse(theURI); + Request.Builder requestBuilder = new Request.Builder().url(url); - if (dictParams != null) { - JSONObject jsonParams = new JSONObject(); - for (String key: dictParams.keySet()){ - jsonParams.put(key, dictParams.get(key)); - } + if(dictParams != null) { + MediaType jsonMediaType = MediaType.parse("application/json; charset=utf-8"); - OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream()); - wr.write(jsonParams.toString()); - wr.flush(); - } + Gson gson = new Gson(); + String json = gson.toJson(dictParams); + + okhttp3.RequestBody requestBody = RequestBody.create(jsonMediaType, json); - InputStream inputStream = connection.getInputStream(); - BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream)); - String line; - while ((line = rd.readLine()) != null) { - chaine.append(line); + requestBuilder.post(requestBody); + } else { + requestBuilder.get(); } - String s = chaine.toString(); - writeFileCache(ctx,theURI,s); + Request request = requestBuilder.build(); + okhttp3.Response response = httpClient.newCall(request).execute(); + + String responseStr = response.body().string(); + + writeFileCache(ctx,theURI,responseStr); if(BuildConfig.DEBUG) { Log.d("UTIL","wrote cache file for:"+theURI); } - return s; + return responseStr; } catch (Exception e) { Log.e("UTIL","downloadFeed() "+e); } @@ -156,8 +154,8 @@ public static String downloadFeed(Context ctx, String theURI, boolean forceUpdat return null; } - public static String getRealStationLink(Context ctx, String stationId){ - String result = Utils.downloadFeed(ctx, RadioBrowserServerManager.getWebserviceEndpoint(ctx, "v2/json/url/" + stationId), true, null); + public static String getRealStationLink(OkHttpClient httpClient, Context ctx, String stationId){ + String result = Utils.downloadFeed(httpClient, ctx, RadioBrowserServerManager.getWebserviceEndpoint(ctx, "v2/json/url/" + stationId), true, null); if (result != null) { JSONObject jsonObj; try { @@ -170,9 +168,9 @@ public static String getRealStationLink(Context ctx, String stationId){ return null; } - public static DataRadioStation getStationByUuid(Context ctx, String stationUuid){ + public static DataRadioStation getStationByUuid(OkHttpClient httpClient, Context ctx, String stationUuid){ Log.w("UTIL","Search by uuid:"+stationUuid); - String result = Utils.downloadFeed(ctx, RadioBrowserServerManager.getWebserviceEndpoint(ctx, "json/stations/byuuid/" + stationUuid), true, null); + String result = Utils.downloadFeed(httpClient, ctx, RadioBrowserServerManager.getWebserviceEndpoint(ctx, "json/stations/byuuid/" + stationUuid), true, null); if (result != null) { try { DataRadioStation[] list = DataRadioStation.DecodeJson(result); @@ -189,14 +187,14 @@ public static DataRadioStation getStationByUuid(Context ctx, String stationUuid) return null; } - public static void Play(final DataRadioStation station, final Context context) { + public static void Play(final OkHttpClient httpClient, final DataRadioStation station, final Context context) { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); boolean play_external = sharedPref.getBoolean("play_external", false); - Play(station,context,play_external); + Play(httpClient, station,context,play_external); } - public static void Play(final DataRadioStation station, final Context context, final boolean external) { + public static void Play(final OkHttpClient httpClient, final DataRadioStation station, final Context context, final boolean external) { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); final boolean warn_no_wifi = sharedPref.getBoolean("warn_no_wifi", false); if (warn_no_wifi && !Utils.hasWifiConnection(context)) { @@ -214,22 +212,22 @@ public static void Play(final DataRadioStation station, final Context context, f .setNegativeButton(android.R.string.cancel, null) // do not play on cancel .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - playInternal(station, context, external); + playInternal(httpClient, station, context, external); } }) .create() .show(); } else { - playInternal(station, context, external); + playInternal(httpClient, station, context, external); } } - private static void playInternal(final DataRadioStation station, final Context context, final boolean external) { + private static void playInternal(final OkHttpClient httpClient, final DataRadioStation station, final Context context, final boolean external) { context.sendBroadcast(new Intent(ActivityMain.ACTION_SHOW_LOADING)); new AsyncTask() { @Override protected String doInBackground(Void... params) { - return Utils.getRealStationLink(context.getApplicationContext(), station.ID); + return Utils.getRealStationLink(httpClient, context.getApplicationContext(), station.ID); } @Override @@ -401,4 +399,33 @@ public static String formatStringWithNamedArgs(String format, Map implements TimePickerDialog.OnTimeSetListener, RecyclerItemSwipeHelper.SwipeCallback { @@ -438,10 +440,14 @@ private void openStationHomeUrl(final DataRadioStation station) { private void retrieveAndCopyStreamUrlToClipboard(final DataRadioStation station) { getContext().sendBroadcast(new Intent(ActivityMain.ACTION_SHOW_LOADING)); + + final RadioDroidApp radioDroidApp = (RadioDroidApp) getContext().getApplicationContext(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + new AsyncTask() { @Override protected String doInBackground(Void... params) { - return Utils.getRealStationLink(getContext().getApplicationContext(), station.ID); + return Utils.getRealStationLink(httpClient, radioDroidApp, station.ID); } @Override @@ -475,10 +481,13 @@ private void star(DataRadioStation station) { } private void vote(final String stationID) { + final RadioDroidApp radioDroidApp = (RadioDroidApp) getContext().getApplicationContext(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + new AsyncTask() { @Override protected String doInBackground(Void... params) { - return Utils.downloadFeed(activity, RadioBrowserServerManager.getWebserviceEndpoint(activity,"json/vote/" + stationID), true, null); + return Utils.downloadFeed(httpClient, activity, RadioBrowserServerManager.getWebserviceEndpoint(activity,"json/vote/" + stationID), true, null); } @Override @@ -517,10 +526,14 @@ private void setAsAlarm(DataRadioStation station) { private void share(final DataRadioStation station) { getContext().sendBroadcast(new Intent(ActivityMain.ACTION_SHOW_LOADING)); + + final RadioDroidApp radioDroidApp = (RadioDroidApp) getContext().getApplicationContext(); + final OkHttpClient httpClient = radioDroidApp.getHttpClient(); + new AsyncTask() { @Override protected String doInBackground(Void... params) { - return Utils.getRealStationLink(getContext().getApplicationContext(), station.ID); + return Utils.getRealStationLink(httpClient, radioDroidApp, station.ID); } @Override diff --git a/app/src/main/java/net/programmierecke/radiodroid2/players/RadioPlayer.java b/app/src/main/java/net/programmierecke/radiodroid2/players/RadioPlayer.java index 8b3cc716f..e67c9e1ed 100644 --- a/app/src/main/java/net/programmierecke/radiodroid2/players/RadioPlayer.java +++ b/app/src/main/java/net/programmierecke/radiodroid2/players/RadioPlayer.java @@ -13,6 +13,7 @@ import net.programmierecke.radiodroid2.BuildConfig; import net.programmierecke.radiodroid2.HttpClient; +import net.programmierecke.radiodroid2.RadioDroidApp; import net.programmierecke.radiodroid2.Utils; import net.programmierecke.radiodroid2.data.ShoutcastInfo; import net.programmierecke.radiodroid2.data.StreamLiveInfo; @@ -52,7 +53,6 @@ public interface PlayerListener { } private PlayerWrapper player; - private OkHttpClient httpClient; private Context mainContext; private String streamName; @@ -89,10 +89,6 @@ public RadioPlayer(Context mainContext) { playerThreadHandler = new Handler(playerThread.getLooper()); - httpClient = HttpClient.getInstance().newBuilder() - .retryOnConnectionFailure(true) - .build(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { player = new ExoPlayerWrapper(); } else { @@ -113,7 +109,9 @@ public final void play(final String stationURL, final String streamName, final b final int connectTimeout = prefs.getInt("stream_connect_timeout", 4); final int readTimeout = prefs.getInt("stream_read_timeout", 10); - final OkHttpClient customizedHttpClient = httpClient.newBuilder() + RadioDroidApp radioDroidApp = (RadioDroidApp) mainContext.getApplicationContext(); + + final OkHttpClient customizedHttpClient = radioDroidApp.newHttpClient() .connectTimeout(connectTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) .build(); diff --git a/app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettings.java b/app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettings.java new file mode 100644 index 000000000..696875906 --- /dev/null +++ b/app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettings.java @@ -0,0 +1,30 @@ +package net.programmierecke.radiodroid2.proxy; + +import android.content.SharedPreferences; + +import com.google.gson.Gson; + +import java.net.Proxy; + +public class ProxySettings { + private final static String PREFERENCES_KEY = "proxySettings"; + + public String host; + public int port; + public String login; + public String password; + public Proxy.Type type; + + public static ProxySettings fromPreferences(SharedPreferences sharedPref) { + Gson gson = new Gson(); + String jsonStr = sharedPref.getString(PREFERENCES_KEY, ""); + + return gson.fromJson(jsonStr, ProxySettings.class); + } + + public void toPreferences(SharedPreferences.Editor sharedPrefEditor) { + Gson gson = new Gson(); + String jsonStr = gson.toJson(this); + sharedPrefEditor.putString(PREFERENCES_KEY, jsonStr); + } +} diff --git a/app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettingsDialog.java b/app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettingsDialog.java new file mode 100644 index 000000000..9690dd437 --- /dev/null +++ b/app/src/main/java/net/programmierecke/radiodroid2/proxy/ProxySettingsDialog.java @@ -0,0 +1,223 @@ +package net.programmierecke.radiodroid2.proxy; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v7.app.AlertDialog; +import android.support.v7.preference.PreferenceManager; +import android.support.v7.widget.AppCompatSpinner; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import net.programmierecke.radiodroid2.R; +import net.programmierecke.radiodroid2.RadioDroidApp; +import net.programmierecke.radiodroid2.Utils; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.net.Proxy; +import java.util.concurrent.TimeUnit; + +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public class ProxySettingsDialog extends DialogFragment { + + final static private String TEST_ADDRESS = "http://radio-browser.info"; + + private EditText editProxyHost; + private EditText editProxyPort; + private AppCompatSpinner spinnerProxyType; + private EditText editLogin; + private EditText editProxyPassword; + private TextView textProxyTestResult; + + private ArrayAdapter proxyTypeAdapter; + + private AsyncTask proxyTestTask; + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + + View layout = inflater.inflate(R.layout.dialog_proxy_settings, null); + + editProxyHost = layout.findViewById(R.id.edit_proxy_host); + editProxyPort = layout.findViewById(R.id.edit_proxy_port); + spinnerProxyType = layout.findViewById(R.id.spinner_proxy_type); + editLogin = layout.findViewById(R.id.edit_proxy_login); + editProxyPassword = layout.findViewById(R.id.edit_proxy_password); + textProxyTestResult = layout.findViewById(R.id.text_test_proxy_result); + + proxyTypeAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, + new Proxy.Type[]{Proxy.Type.DIRECT, Proxy.Type.HTTP, Proxy.Type.SOCKS}); + + spinnerProxyType.setAdapter(proxyTypeAdapter); + + { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext()); + ProxySettings proxySettings = ProxySettings.fromPreferences(sharedPref); + + if (proxySettings != null) { + editProxyHost.setText(proxySettings.host); + editProxyPort.setText(Integer.toString(proxySettings.port)); + editLogin.setText(proxySettings.login); + editProxyPassword.setText(proxySettings.password); + spinnerProxyType.setSelection(proxyTypeAdapter.getPosition(proxySettings.type)); + } + } + + final Dialog dialog = builder.setView(layout) + .setPositiveButton(R.string.action_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sharedPref.edit(); + + ProxySettings proxySettings = createProxySettings(); + proxySettings.toPreferences(editor); + editor.apply(); + + RadioDroidApp radioDroidApp = (RadioDroidApp) getActivity().getApplication(); + radioDroidApp.rebuildHttpClient(); + } + }) + .setNegativeButton(R.string.action_cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + ProxySettingsDialog.this.getDialog().cancel(); + } + }) + .setNeutralButton(R.string.settings_proxy_action_test, null) + .create(); + + dialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialogInterface) { + Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_NEUTRAL); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + ProxySettings proxySettings = createProxySettings(); + testProxy(proxySettings); + } + }); + } + }); + + return dialog; + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + + if (proxyTestTask != null) { + proxyTestTask.cancel(true); + } + } + + private ProxySettings createProxySettings() { + ProxySettings settings = new ProxySettings(); + + settings.host = editProxyHost.getText().toString(); + settings.port = Integer.parseInt(editProxyPort.getText().toString()); + settings.login = editLogin.getText().toString(); + settings.password = editProxyPassword.getText().toString(); + settings.type = proxyTypeAdapter.getItem(spinnerProxyType.getSelectedItemPosition()); + + return settings; + } + + private static class ConnectionTesterTask extends AsyncTask { + private WeakReference textProxyTestResult; + + private OkHttpClient okHttpClient; + private Call call; + + private String connectionSuccessStr; + private String connectionFailedStr; + + private boolean requestSucceeded = false; + private String errorStr; + + private ConnectionTesterTask(@NonNull RadioDroidApp radioDroidApp, @NonNull TextView textProxyTestResult, + @NonNull ProxySettings proxySettings) { + this.textProxyTestResult = new WeakReference<>(textProxyTestResult); + + textProxyTestResult.setText(""); + + connectionSuccessStr = radioDroidApp.getString(R.string.settings_proxy_working, TEST_ADDRESS); + connectionFailedStr = radioDroidApp.getString(R.string.settings_proxy_not_working); + + OkHttpClient.Builder builder = radioDroidApp.newHttpClient() + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS); + + Utils.setOkHttpProxy(builder, proxySettings); + okHttpClient = builder.build(); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + Request.Builder builder = new Request.Builder().url(TEST_ADDRESS); + call = okHttpClient.newCall(builder.build()); + } + + @Override + protected Void doInBackground(Void... voids) { + try { + Response response = call.execute(); + requestSucceeded = response.isSuccessful(); + if (!requestSucceeded) { + errorStr = response.message(); + } + } catch (IOException e) { + requestSucceeded = false; + errorStr = e.getMessage(); + } + + return null; + } + + @Override + protected void onPostExecute(Void v) { + super.onPostExecute(v); + + TextView textResult = textProxyTestResult.get(); + if (textResult == null) { + return; + } + + if (requestSucceeded) { + textResult.setText(connectionSuccessStr); + } else { + textResult.setText(String.format(connectionFailedStr, TEST_ADDRESS, errorStr)); + } + } + } + + private void testProxy(@NonNull ProxySettings proxySettings) { + if (proxyTestTask != null) { + proxyTestTask.cancel(true); + } + + RadioDroidApp radioDroidApp = (RadioDroidApp) getActivity().getApplication(); + proxyTestTask = new ConnectionTesterTask(radioDroidApp, textProxyTestResult, proxySettings); + proxyTestTask.execute(); + } +} diff --git a/app/src/main/res/layout/dialog_proxy_settings.xml b/app/src/main/res/layout/dialog_proxy_settings.xml new file mode 100644 index 000000000..6b6b0fde2 --- /dev/null +++ b/app/src/main/res/layout/dialog_proxy_settings.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_server_alert.xml b/app/src/main/res/layout/layout_server_alert.xml index 1ea7865dd..8bcb22246 100644 --- a/app/src/main/res/layout/layout_server_alert.xml +++ b/app/src/main/res/layout/layout_server_alert.xml @@ -28,7 +28,7 @@ android:layout_margin="10dp" android:maxLines="1" android:inputType="text" - android:hint="@string/alert_select_mpd_server_hostname" + android:hint="@string/hostname" android:layout_toLeftOf="@id/mpd_server_port" android:layout_toStartOf="@id/mpd_server_port"/> @@ -39,7 +39,7 @@ android:textSize="15sp" android:layout_margin="10dp" android:maxLines="1" - android:hint="@string/alert_select_mpd_server_port" + android:hint="@string/port" android:text="6600" android:layout_alignParentRight="true" android:layout_alignParentEnd="true"/> diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 1205c0ad5..c134c0461 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -157,8 +157,8 @@ Ποιον εξυπηρετητή; Όνομα του εξυπηρετητή - Όνομα του οικοδεσπότη - Θύρα + Όνομα του οικοδεσπότη + Θύρα Προσθήκη Αποθήκευση diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 02d8f4531..db657404d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -136,8 +136,8 @@ ¿En qué servidor? Nombre del servidor - Nombre del host - Puerto + Nombre del host + Puerto Añadir Guardar diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 50f7a727d..21aa03a4a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -135,8 +135,8 @@ Выберите сервер Имя сервера - Имя хоста - Порт + Имя хоста + Порт Добавить Сохранить diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index be54fc3e2..9d0d05bda 100755 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -155,8 +155,8 @@ Ktorý server? Názouv servera - Názov hostiteľa - Port + Názov hostiteľa + Port Pridať Uložiť diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 8a9c8861b..4d9f26813 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -144,8 +144,8 @@ Hangi sunucu? Sunucu adı - Alan adı - Port + Alan adı + Port Ekle Kaydet diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5f5f789f8..42e20ab37 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -149,8 +149,8 @@ 请选择服务器 服务器名 - 主机名 - 端口 + 主机名 + 端口 添加 保存 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e798f63d9..0f23cb559 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ Delete Delete history Delete favorites + OK Cancel TopClick TopVote @@ -110,6 +111,12 @@ Stream read timeout Stream retry timeout Reconnects delay + Proxy + Login + Password + Test + Successfully connected to %s + Failed to connect to %s\n%s %d seconds %d milliseconds @@ -149,8 +156,8 @@ Which server? Server name - Hostname - Port + Hostname + Port Add Save diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 10d5db939..e0d85750d 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -169,6 +169,9 @@ android:maxLength="8" android:summary="@string/settings_milliseconds_format" android:title="@string/settings_retry_delay" /> + From b76114f9570f2ccf09304bf0af849b513145d904 Mon Sep 17 00:00:00 2001 From: werman Date: Sun, 24 Jun 2018 23:08:44 +0300 Subject: [PATCH 2/2] Fix Hungarian localization file --- app/src/main/res/values-hu/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 15998b126..864e0982a 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -102,7 +102,7 @@ Lejátszás leállítása %1$s perc után Lejátszó Külső megnyitása - Az államosokon történő kattintás külső appot nyit meg + Az államosokon történő kattintás külső appot nyit meg Hangszínszabályzó Kapcsolódás @@ -173,7 +173,7 @@ leállítva lejátszás rögzítés - lejátszás és rögzítés + lejátszás és rögzítés Átküldött adatok: %1$s Rögzítés ide:\n%1$s Legutóbbi rögzítés:\n%1$s @@ -190,7 +190,7 @@ Kevesebb Ismétlés Ne legyen ismétlés - Csökkenő népszerűség + Csökkenő népszerűség Növekvő népszerűség Stabil népszerűség @@ -198,7 +198,7 @@ 5A97BAE4 Zenelejátszó démon - Saját kiszolgálók + Saját kiszolgálók MPD nincs csatlakoztatva MPD csatlakoztatva Kapcsolódva a kiszolgálóhoz: %1$s