diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java index 6e9f712f9..198e71d53 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java @@ -12,12 +12,13 @@ public interface TorConstants { int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds - String PREF_TOR_NETWORK = "network"; + String PREF_TOR_NETWORK = "network2"; String PREF_TOR_PORT = "port"; - String PREF_TOR_DISABLE_BLOCKED = "disableWhenBlocked"; + String PREF_TOR_MOBILE = "useMobileData"; - int PREF_TOR_NETWORK_NEVER = 0; - int PREF_TOR_NETWORK_WIFI = 1; - int PREF_TOR_NETWORK_ALWAYS = 2; + int PREF_TOR_NETWORK_AUTOMATIC = 0; + int PREF_TOR_NETWORK_WITHOUT_BRIDGES = 1; + int PREF_TOR_NETWORK_WITH_BRIDGES = 2; + int PREF_TOR_NETWORK_NEVER = 3; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java index 3c6f4cb04..0cbacd3fe 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tor/TorPlugin.java @@ -64,11 +64,11 @@ import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS; import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY; import static org.briarproject.bramble.api.plugin.TorConstants.CONTROL_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.ID; -import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_DISABLE_BLOCKED; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK; -import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_AUTOMATIC; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_NEVER; -import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WITH_BRIDGES; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT; import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION; import static org.briarproject.bramble.util.LogUtils.logException; @@ -170,6 +170,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { if (!assetsAreUpToDate()) installAssets(); if (cookieFile.exists() && !cookieFile.delete()) LOG.warning("Old auth cookie not deleted"); + // Migrate old settings before having a chance to stop + migrateSettings(); // Start a new Tor process LOG.info("Starting Tor"); String torPath = torFile.getAbsolutePath(); @@ -629,9 +631,11 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { boolean blocked = circumventionProvider.isTorProbablyBlocked(country); Settings s = callback.getSettings(); - int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS); - boolean disableWhenBlocked = - s.getBoolean(PREF_TOR_DISABLE_BLOCKED, true); + int network = + s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_AUTOMATIC); + boolean useMobile = s.getBoolean(PREF_TOR_MOBILE, true); + boolean bridgesWork = circumventionProvider.doBridgesWork(country); + boolean automatic = network == PREF_TOR_NETWORK_AUTOMATIC; if (LOG.isLoggable(INFO)) { LOG.info("Online: " + online + ", wifi: " + wifi); @@ -643,25 +647,20 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { if (!online) { LOG.info("Disabling network, device is offline"); enableNetwork(false); - } else if (network == PREF_TOR_NETWORK_NEVER - || (network == PREF_TOR_NETWORK_WIFI && !wifi)) { + } else if (network == PREF_TOR_NETWORK_NEVER || + (!useMobile && !wifi)) { LOG.info("Disabling network due to data setting"); enableNetwork(false); - } else if (blocked) { - if (circumventionProvider.doBridgesWork(country)) { - LOG.info("Enabling network, using bridges"); - enableBridges(true); - enableNetwork(true); - } else if (disableWhenBlocked) { - LOG.info("Disabling network, country is blocked"); - enableNetwork(false); - } else { - LOG.info("Enabling network but country is blocked"); - enableBridges(false); - enableNetwork(true); - } + } else if (automatic && blocked && !bridgesWork) { + LOG.info("Disabling network, country is blocked"); + enableNetwork(false); + } else if (network == PREF_TOR_NETWORK_WITH_BRIDGES || + (automatic && bridgesWork)) { + LOG.info("Enabling network, using bridges"); + enableBridges(true); + enableNetwork(true); } else { - LOG.info("Enabling network"); + LOG.info("Enabling network, not using bridges"); enableBridges(false); enableNetwork(true); } @@ -671,6 +670,21 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener { }); } + // TODO remove when sufficient time has passed. Added 2018-08-15 + private void migrateSettings() { + Settings sOld = callback.getSettings(); + int oldNetwork = sOld.getInt("network", -1); + if (oldNetwork == -1) return; + Settings s = new Settings(); + if (oldNetwork == 0) { + s.putInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_NEVER); + } else if (oldNetwork == 1) { + s.putBoolean(PREF_TOR_MOBILE, false); + } + s.putInt("network", -1); + callback.mergeSettings(s); + } + private static class ConnectionStatus { // All of the following are locking: this diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index e531f295c..771a2ad57 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -22,6 +22,8 @@ import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.plugin.tor.CircumventionProvider; import org.briarproject.briar.BriarCoreEagerSingletons; import org.briarproject.briar.BriarCoreModule; import org.briarproject.briar.android.login.SignInReminderReceiver; @@ -149,6 +151,10 @@ public interface AndroidComponent LockManager lockManager(); + LocationUtils locationUtils(); + + CircumventionProvider circumventionProvider(); + void inject(SignInReminderReceiver briarService); void inject(BriarService briarService); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index 1f52854f3..0904e1b97 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -35,6 +35,8 @@ import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.SettingsManager; import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.bramble.api.system.LocationUtils; +import org.briarproject.bramble.plugin.tor.CircumventionProvider; import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.R; import org.briarproject.briar.android.Localizer; @@ -43,7 +45,6 @@ import org.briarproject.briar.android.util.UiUtils; import org.briarproject.briar.android.util.UserFeedback; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.logging.Logger; @@ -68,19 +69,15 @@ import static android.provider.Settings.EXTRA_CHANNEL_ID; import static android.provider.Settings.System.DEFAULT_NOTIFICATION_URI; import static android.support.v4.view.ViewCompat.LAYOUT_DIRECTION_LTR; import static android.widget.Toast.LENGTH_SHORT; -import static java.util.Arrays.asList; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENABLE; -import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_DISABLE_BLOCKED; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_MOBILE; import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK; -import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_ALWAYS; -import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BLOCKED; -import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BRIDGES; +import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_AUTOMATIC; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; -import static org.briarproject.bramble.util.StringUtils.join; import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_DARK_THEME; import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_PIN_LOCK; import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_SIGN_IN_REMINDER; @@ -113,7 +110,8 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String LANGUAGE = "pref_key_language"; public static final String PREF_SCREEN_LOCK = "pref_key_lock"; public static final String NOTIFY_SIGN_IN = "pref_key_notify_sign_in"; - public static final String TOR_LOCATION = "pref_key_tor_location"; + public static final String TOR_NETWORK = "pref_key_tor_network"; + public static final String TOR_MOBILE = "pref_key_tor_mobile_data"; private static final Logger LOG = Logger.getLogger(SettingsFragment.class.getName()); @@ -122,7 +120,7 @@ public class SettingsFragment extends PreferenceFragmentCompat private ListPreference language; private ListPreference enableBluetooth; private ListPreference torNetwork; - private SwitchPreference torBlocked; + private SwitchPreference torMobile; private SwitchPreference screenLock; private SwitchPreference notifyPrivateMessages; private SwitchPreference notifyGroupMessages; @@ -130,6 +128,7 @@ public class SettingsFragment extends PreferenceFragmentCompat private SwitchPreference notifyBlogPosts; private SwitchPreference notifyVibration; private SwitchPreference notifyLockscreen; + private Preference notifySound; // Fields that are accessed from background threads must be volatile @@ -138,6 +137,10 @@ public class SettingsFragment extends PreferenceFragmentCompat volatile SettingsManager settingsManager; @Inject volatile EventBus eventBus; + @Inject + LocationUtils locationUtils; + @Inject + CircumventionProvider circumventionProvider; @Inject AndroidExecutor androidExecutor; @@ -160,9 +163,8 @@ public class SettingsFragment extends PreferenceFragmentCompat ListPreference theme = (ListPreference) findPreference("pref_key_theme"); enableBluetooth = (ListPreference) findPreference("pref_key_bluetooth"); - torNetwork = (ListPreference) findPreference("pref_key_tor_network"); - torBlocked = (SwitchPreference) findPreference(TOR_LOCATION); - setBlockedCountries(); + torNetwork = (ListPreference) findPreference(TOR_NETWORK); + torMobile = (SwitchPreference) findPreference(TOR_MOBILE); SwitchPreference notifySignIn = (SwitchPreference) findPreference(NOTIFY_SIGN_IN); screenLock = (SwitchPreference) findPreference(PREF_SCREEN_LOCK); @@ -201,7 +203,7 @@ public class SettingsFragment extends PreferenceFragmentCompat }); enableBluetooth.setOnPreferenceChangeListener(this); torNetwork.setOnPreferenceChangeListener(this); - torBlocked.setOnPreferenceChangeListener(this); + torMobile.setOnPreferenceChangeListener(this); screenLock.setOnPreferenceChangeListener(this); if (SDK_INT >= 21) { notifyLockscreen.setVisible(true); @@ -304,30 +306,33 @@ public class SettingsFragment extends PreferenceFragmentCompat return direction == LAYOUT_DIRECTION_LTR; } - private void setBlockedCountries() { - List countryCodes = new ArrayList<>(asList(BLOCKED)); - countryCodes.removeAll(asList(BRIDGES)); - // Look up country names in the user's chosen language if available - Locale[] locales = Locale.getAvailableLocales(); - List countries = new ArrayList<>(countryCodes.size()); - for (String countryCode : countryCodes) { - boolean found = false; - for (Locale locale : locales) { - if (locale.getCountry().equalsIgnoreCase(countryCode)) { - countries.add(locale.getDisplayCountry()); - found = true; - break; - } - } - if (!found) { - if (LOG.isLoggable(INFO)) - LOG.info("No locale for " + countryCode); - countries.add(countryCode); + private void setTorNetworkSummary(int torNetworkSetting) { + if (torNetworkSetting != PREF_TOR_NETWORK_AUTOMATIC) { + torNetwork.setSummary("%s"); // use setting value + return; + } + + // Look up country name in the user's chosen language if available + String country = locationUtils.getCurrentCountry(); + String countryName = getString(R.string.tor_network_country_unknown); + for (Locale locale : Locale.getAvailableLocales()) { + if (locale.getCountry().equalsIgnoreCase(country)) { + countryName = locale.getDisplayCountry(); + break; } } - Collections.sort(countries); - String format = getString(R.string.tor_location_setting_hint_format); - torBlocked.setSummary(String.format(format, join(countries, ", "))); + boolean blocked = + circumventionProvider.isTorProbablyBlocked(country); + boolean useBridges = circumventionProvider.doBridgesWork(country); + String setting = getString(R.string.tor_network_setting_without_bridges); + if (blocked && useBridges) { + setting = getString(R.string.tor_network_setting_with_bridges); + } else if (blocked) { + setting = getString(R.string.tor_network_setting_never); + } + torNetwork.setSummary( + getString(R.string.tor_network_setting_summary, setting, + countryName)); } private void loadSettings() { @@ -342,11 +347,10 @@ public class SettingsFragment extends PreferenceFragmentCompat boolean btSetting = btSettings.getBoolean(PREF_BT_ENABLE, false); int torNetworkSetting = torSettings.getInt(PREF_TOR_NETWORK, - PREF_TOR_NETWORK_ALWAYS); - boolean torBlockedSetting = - torSettings.getBoolean(PREF_TOR_DISABLE_BLOCKED, true); - displaySettings(btSetting, torNetworkSetting, - torBlockedSetting); + PREF_TOR_NETWORK_AUTOMATIC); + boolean torMobileSetting = + torSettings.getBoolean(PREF_TOR_MOBILE, true); + displaySettings(btSetting, torNetworkSetting, torMobileSetting); } catch (DbException e) { logException(LOG, WARNING, e); } @@ -354,11 +358,12 @@ public class SettingsFragment extends PreferenceFragmentCompat } private void displaySettings(boolean btSetting, int torNetworkSetting, - boolean torBlockedSetting) { + boolean torMobileSetting) { listener.runOnUiThreadUnlessDestroyed(() -> { enableBluetooth.setValue(Boolean.toString(btSetting)); torNetwork.setValue(Integer.toString(torNetworkSetting)); - torBlocked.setChecked(torBlockedSetting); + setTorNetworkSummary(torNetworkSetting); + torMobile.setChecked(torMobileSetting); displayScreenLockSetting(); if (SDK_INT < 26) { @@ -421,7 +426,7 @@ public class SettingsFragment extends PreferenceFragmentCompat // - pref_key_lock (screenLock -> displayScreenLockSetting()) enableBluetooth.setEnabled(enabled); torNetwork.setEnabled(enabled); - torBlocked.setEnabled(enabled); + torMobile.setEnabled(enabled); if (!enabled) screenLock.setEnabled(false); notifyPrivateMessages.setEnabled(enabled); notifyGroupMessages.setEnabled(enabled); @@ -501,9 +506,10 @@ public class SettingsFragment extends PreferenceFragmentCompat } else if (preference == torNetwork) { int torNetworkSetting = Integer.valueOf((String) newValue); storeTorNetworkSetting(torNetworkSetting); - } else if (preference == torBlocked) { - boolean torBlockedSetting = (Boolean) newValue; - storeTorBlockedSetting(torBlockedSetting); + setTorNetworkSummary(torNetworkSetting); + } else if (preference == torMobile) { + boolean torMobileSetting = (Boolean) newValue; + storeTorMobileSetting(torMobileSetting); } else if (preference == screenLock) { Settings s = new Settings(); s.putBoolean(PREF_SCREEN_LOCK, (Boolean) newValue); @@ -562,9 +568,9 @@ public class SettingsFragment extends PreferenceFragmentCompat mergeSettings(s, TOR_NAMESPACE); } - private void storeTorBlockedSetting(boolean torBlockedSetting) { + private void storeTorMobileSetting(boolean torMobileSetting) { Settings s = new Settings(); - s.putBoolean(PREF_TOR_DISABLE_BLOCKED, torBlockedSetting); + s.putBoolean(PREF_TOR_MOBILE, torMobileSetting); mergeSettings(s, TOR_NAMESPACE); } diff --git a/briar-android/src/main/res/values/arrays.xml b/briar-android/src/main/res/values/arrays.xml index d4001a3c9..f1a527523 100644 --- a/briar-android/src/main/res/values/arrays.xml +++ b/briar-android/src/main/res/values/arrays.xml @@ -8,16 +8,20 @@ @string/bluetooth_setting_enabled @string/bluetooth_setting_disabled + + @string/tor_network_setting_automatic + @string/tor_network_setting_without_bridges + @string/tor_network_setting_with_bridges @string/tor_network_setting_never - @string/tor_network_setting_wifi - @string/tor_network_setting_always 0 1 2 + 3 + default en-US diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 45c9ce6e7..746094f0b 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -348,12 +348,16 @@ Connect via Bluetooth Whenever contacts are nearby Only when adding contacts - Connect via Tor - Never - Only when using Wi-Fi - When using Wi-Fi or mobile data - Disable Tor based on location - Disable Tor in countries where it is likely to be blocked (%1$s) + Connect via Internet (Tor) + Automatic based on location + Use Tor without bridges + Use Tor with bridges + Don\'t connect + + Automatic: %1$s (in %2$s) + + unknown + Use Mobile Data Security diff --git a/briar-android/src/main/res/xml/settings.xml b/briar-android/src/main/res/xml/settings.xml index 1238f65e9..a0a4477f8 100644 --- a/briar-android/src/main/res/xml/settings.xml +++ b/briar-android/src/main/res/xml/settings.xml @@ -36,7 +36,7 @@ android:title="@string/bluetooth_setting"/> + android:title="@string/tor_mobile_data_title"/>