diff --git a/app/src/main/java/eu/faircode/email/EmailService.java b/app/src/main/java/eu/faircode/email/EmailService.java index 1be0ae172d..578103c3ce 100644 --- a/app/src/main/java/eu/faircode/email/EmailService.java +++ b/app/src/main/java/eu/faircode/email/EmailService.java @@ -97,11 +97,9 @@ public class EmailService implements AutoCloseable { static final int PURPOSE_USE = 2; static final int PURPOSE_SEARCH = 3; + final static int DEFAULT_CONNECT_TIMEOUT = 20; // seconds + private final static int SEARCH_TIMEOUT = 2 * 60 * 1000; // milliseconds - private final static int CONNECT_TIMEOUT = 20 * 1000; // milliseconds - private final static int CONNECT_TIMEOUT_CHECK = 20 * 1000; // milliseconds - private final static int WRITE_TIMEOUT = 60 * 1000; // milliseconds - private final static int READ_TIMEOUT = 60 * 1000; // milliseconds private final static int FETCH_SIZE = 1024 * 1024; // bytes, default 16K private final static int POOL_TIMEOUT = 45 * 1000; // milliseconds, default 45 sec @@ -155,20 +153,17 @@ public class EmailService implements AutoCloseable { properties.put("mail." + protocol + ".sasl.realm", realm == null ? "" : realm); properties.put("mail." + protocol + ".auth.ntlm.domain", realm == null ? "" : realm); - // TODO: make timeouts configurable? // writetimeout: one thread overhead + int timeout = prefs.getInt("timeout", DEFAULT_CONNECT_TIMEOUT) * 1000; + Log.i("Timeout=" + timeout); if (purpose == PURPOSE_SEARCH) { - properties.put("mail." + protocol + ".connectiontimeout", Integer.toString(CONNECT_TIMEOUT)); + properties.put("mail." + protocol + ".connectiontimeout", Integer.toString(timeout)); properties.put("mail." + protocol + ".writetimeout", Integer.toString(SEARCH_TIMEOUT)); properties.put("mail." + protocol + ".timeout", Integer.toString(SEARCH_TIMEOUT)); - } else if (purpose == PURPOSE_CHECK) { - properties.put("mail." + protocol + ".connectiontimeout", Integer.toString(CONNECT_TIMEOUT_CHECK)); - properties.put("mail." + protocol + ".writetimeout", Integer.toString(WRITE_TIMEOUT)); - properties.put("mail." + protocol + ".timeout", Integer.toString(READ_TIMEOUT)); } else { - properties.put("mail." + protocol + ".connectiontimeout", Integer.toString(CONNECT_TIMEOUT)); - properties.put("mail." + protocol + ".writetimeout", Integer.toString(WRITE_TIMEOUT)); - properties.put("mail." + protocol + ".timeout", Integer.toString(READ_TIMEOUT)); + properties.put("mail." + protocol + ".connectiontimeout", Integer.toString(timeout)); + properties.put("mail." + protocol + ".writetimeout", Integer.toString(timeout * 2)); + properties.put("mail." + protocol + ".timeout", Integer.toString(timeout * 2)); } if (debug && BuildConfig.DEBUG) diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java index 19e566b0d0..17bb26dd23 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java @@ -29,7 +29,9 @@ import android.net.NetworkRequest; import android.os.Build; import android.os.Bundle; import android.provider.Settings; +import android.text.Editable; import android.text.TextUtils; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -56,6 +58,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private Spinner spDownload; private SwitchCompat swRoaming; private SwitchCompat swRlah; + private EditText etTimeout; private SwitchCompat swSslHarden; private SwitchCompat swSocks; private EditText etSocks; @@ -65,7 +68,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private TextView tvConnectionRoaming; private final static String[] RESET_OPTIONS = new String[]{ - "metered", "download", "roaming", "rlah", "ssl_harden", "socks_enabled", "socks_proxy" + "metered", "download", "roaming", "rlah", "timeout", "ssl_harden", "socks_enabled", "socks_proxy" }; @Override @@ -82,6 +85,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre spDownload = view.findViewById(R.id.spDownload); swRoaming = view.findViewById(R.id.swRoaming); swRlah = view.findViewById(R.id.swRlah); + etTimeout = view.findViewById(R.id.etTimeout); swSslHarden = view.findViewById(R.id.swSslHarden); swSocks = view.findViewById(R.id.swSocks); etSocks = view.findViewById(R.id.etSocks); @@ -131,6 +135,31 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre } }); + etTimeout.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + try { + int timeout = (s.length() > 0 ? Integer.parseInt(s.toString()) : 0); + if (timeout == 0) + prefs.edit().remove("timeout").apply(); + else + prefs.edit().putInt("timeout", timeout).apply(); + } catch (NumberFormatException ex) { + Log.e(ex); + } + } + + @Override + public void afterTextChanged(Editable s) { + // Do nothing + } + }); + swSslHarden.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @@ -186,6 +215,9 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre @Override public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if ("timeout".equals(key)) + return; + if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) setOptions(); } @@ -255,6 +287,11 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre swRoaming.setChecked(prefs.getBoolean("roaming", true)); swRlah.setChecked(prefs.getBoolean("rlah", true)); + + int timeout = prefs.getInt("timeout", 0); + etTimeout.setText(timeout == 0 ? null : Integer.toString(timeout)); + etTimeout.setHint(Integer.toString(EmailService.DEFAULT_CONNECT_TIMEOUT)); + swSslHarden.setChecked(prefs.getBoolean("ssl_harden", false)); swSocks.setChecked(prefs.getBoolean("socks_enabled", false)); etSocks.setText(prefs.getString("socks_proxy", null)); diff --git a/app/src/main/res/layout/fragment_options_connection.xml b/app/src/main/res/layout/fragment_options_connection.xml index 39e9058663..8242690595 100644 --- a/app/src/main/res/layout/fragment_options_connection.xml +++ b/app/src/main/res/layout/fragment_options_connection.xml @@ -123,6 +123,41 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/swRlah" /> + + + + + + Automatically download messages and attachments on a metered connection up to Download messages and attachments while roaming Roam like at home + Connection timeout (seconds) Harden SSL connections Use SOCKS proxy Manage connectivity @@ -456,6 +457,7 @@ Metered connections are generally mobile connections or paid Wi-Fi hotspots Disabling this option will disable receiving and sending messages on mobile internet connections Assuming no roaming within the EU + The read/write timeout will be set to the double of the connection timeout. Higher values will result in more battery use. Enabling this will disable weak SSL protocols and ciphers Using a remote proxy server is insecure because proxy connections are not encrypted Messages headers will always be fetched when roaming. You can use the device\'s roaming setting to disable internet while roaming.