diff --git a/app/build.gradle b/app/build.gradle
index 80832e3b..a7ab817b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -35,8 +35,8 @@ android {
applicationId "com.github.catfriend1.syncthingandroid"
minSdkVersion 16
targetSdkVersion 26
- versionCode 4169
- versionName "0.14.51.6"
+ versionCode 4170
+ versionName "0.14.51.7"
testApplicationId 'com.github.catfriend1.syncthingandroid.test'
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
playAccountConfig = playAccountConfigs.defaultAccountConfig
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java b/app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java
index a0fad95d..bb224522 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/DaggerComponent.java
@@ -1,5 +1,6 @@
package com.nutomic.syncthingandroid;
+import com.nutomic.syncthingandroid.activities.DeviceActivity;
import com.nutomic.syncthingandroid.activities.FirstStartActivity;
import com.nutomic.syncthingandroid.activities.FolderActivity;
import com.nutomic.syncthingandroid.activities.FolderPickerActivity;
@@ -26,6 +27,7 @@ public interface DaggerComponent {
void inject(SyncthingApp app);
void inject(MainActivity activity);
void inject(FirstStartActivity activity);
+ void inject(DeviceActivity activity);
void inject(FolderActivity activity);
void inject(FolderPickerActivity activity);
void inject(SyncConditionsActivity activity);
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java
index b7971ae5..ba497076 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/DeviceActivity.java
@@ -4,6 +4,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
@@ -24,10 +25,14 @@ import android.widget.Toast;
import com.google.gson.Gson;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
+
import com.nutomic.syncthingandroid.R;
import com.nutomic.syncthingandroid.model.Connections;
import com.nutomic.syncthingandroid.model.Device;
+import com.nutomic.syncthingandroid.service.Constants;
+import com.nutomic.syncthingandroid.service.RestApi;
import com.nutomic.syncthingandroid.service.SyncthingService;
+import com.nutomic.syncthingandroid.SyncthingApp;
import com.nutomic.syncthingandroid.util.Compression;
import com.nutomic.syncthingandroid.util.TextWatcherAdapter;
import com.nutomic.syncthingandroid.util.Util;
@@ -36,6 +41,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import javax.inject.Inject;
+
import static android.text.TextUtils.isEmpty;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -46,7 +53,11 @@ import static com.nutomic.syncthingandroid.util.Compression.METADATA;
/**
* Shows device details and allows changing them.
*/
-public class DeviceActivity extends SyncthingActivity implements View.OnClickListener {
+public class DeviceActivity extends SyncthingActivity
+ implements
+ View.OnClickListener,
+ SyncthingActivity.OnServiceConnectedListener,
+ SyncthingService.OnServiceStateChangeListener {
public static final String EXTRA_NOTIFICATION_ID =
"com.nutomic.syncthingandroid.activities.DeviceActivity.NOTIFICATION_ID";
@@ -84,10 +95,19 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
private SwitchCompat mDevicePaused;
+ private SwitchCompat mCustomSyncConditionsSwitch;
+
+ private TextView mCustomSyncConditionsDescription;
+
+ private TextView mCustomSyncConditionsDialog;
+
private TextView mSyncthingVersionView;
private View mCompressionContainer;
+ @Inject
+ SharedPreferences mPreferences;
+
private boolean mIsCreateMode;
private boolean mDeviceNeedsToUpdate;
@@ -154,6 +174,12 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
mDevice.paused = isChecked;
mDeviceNeedsToUpdate = true;
break;
+ case R.id.customSyncConditionsSwitch:
+ mCustomSyncConditionsDescription.setEnabled(isChecked);
+ mCustomSyncConditionsDialog.setEnabled(isChecked);
+ // This is needed to display the "discard changes dialog".
+ mDeviceNeedsToUpdate = true;
+ break;
}
}
};
@@ -161,11 +187,12 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ((SyncthingApp) getApplication()).component().inject(this);
setContentView(R.layout.fragment_device);
mIsCreateMode = getIntent().getBooleanExtra(EXTRA_IS_CREATE, false);
- registerOnServiceConnectedListener(this::onServiceConnected);
setTitle(mIsCreateMode ? R.string.add_device : R.string.edit_device);
+ registerOnServiceConnectedListener(this);
mIdContainer = findViewById(R.id.idContainer);
mIdView = findViewById(R.id.id);
@@ -177,9 +204,13 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
mCompressionValueView = findViewById(R.id.compressionValue);
mIntroducerView = findViewById(R.id.introducer);
mDevicePaused = findViewById(R.id.devicePause);
+ mCustomSyncConditionsSwitch = findViewById(R.id.customSyncConditionsSwitch);
+ mCustomSyncConditionsDescription = findViewById(R.id.customSyncConditionsDescription);
+ mCustomSyncConditionsDialog = findViewById(R.id.customSyncConditionsDialog);
mSyncthingVersionView = findViewById(R.id.syncthingVersion);
mQrButton.setOnClickListener(this);
+ mCustomSyncConditionsDialog.setOnClickListener(view -> onCustomSyncConditionsDialogClick());
mCompressionContainer.setOnClickListener(this);
if (savedInstanceState != null){
@@ -198,6 +229,19 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
}
}
+ /**
+ * Invoked after user clicked on the {@link mCustomSyncConditionsDialog} label.
+ */
+ private void onCustomSyncConditionsDialogClick() {
+ startActivityForResult(
+ SyncConditionsActivity.createIntent(
+ this, Constants.PREF_OBJECT_PREFIX_DEVICE + mDevice.deviceID, mDevice.name
+ ),
+ 0
+ );
+ return;
+ }
+
private void restoreDialogStates(Bundle savedInstanceState) {
if (savedInstanceState.getBoolean(IS_SHOWING_COMPRESSION_DIALOG)){
showCompressionDialog();
@@ -257,20 +301,32 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
Util.dismissDialogSafe(mDeleteDialog, this);
}
- private void onServiceConnected() {
+ /**
+ * Register for service state change events.
+ */
+ @Override
+ public void onServiceConnected() {
Log.v(TAG, "onServiceConnected");
SyncthingService syncthingService = (SyncthingService) getService();
syncthingService.getNotificationHandler().cancelConsentNotification(getIntent().getIntExtra(EXTRA_NOTIFICATION_ID, 0));
- syncthingService.registerOnServiceStateChangeListener(this::onServiceStateChange);
+ syncthingService.registerOnServiceStateChangeListener(this);
}
/**
* Sets version and current address of the device.
- *
* NOTE: This is only called once on startup, should be called more often to properly display
* version/address changes.
*/
private void onReceiveConnections(Connections connections) {
+ if (connections == null || connections.connections == null) {
+ Log.e(TAG, "onReceiveConnections: connections == null || connections.connections == null");
+ return;
+ }
+ if (mDevice == null) {
+ Log.e(TAG, "onReceiveConnections: mDevice == null");
+ return;
+ }
+
boolean viewsExist = mSyncthingVersionView != null && mCurrentAddressView != null;
if (viewsExist && connections.connections.containsKey(mDevice.deviceID)) {
mCurrentAddressView.setVisibility(VISIBLE);
@@ -280,18 +336,21 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
}
}
- private void onServiceStateChange(SyncthingService.State currentState) {
+ @Override
+ public void onServiceStateChange(SyncthingService.State currentState) {
if (currentState != ACTIVE) {
finish();
return;
}
if (!mIsCreateMode) {
- List devices = getApi().getDevices(false);
+ RestApi restApi = getApi(); // restApi != null because of State.ACTIVE
+ List devices = restApi.getDevices(false);
+ String passedId = getIntent().getStringExtra(EXTRA_DEVICE_ID);
mDevice = null;
- for (Device device : devices) {
- if (device.deviceID.equals(getIntent().getStringExtra(EXTRA_DEVICE_ID))) {
- mDevice = device;
+ for (Device currentDevice : devices) {
+ if (currentDevice.deviceID.equals(passedId)) {
+ mDevice = currentDevice;
break;
}
}
@@ -300,10 +359,10 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
finish();
return;
}
+ if (restApi != null) {
+ restApi.getConnections(this::onReceiveConnections);
+ }
}
-
- getApi().getConnections(this::onReceiveConnections);
-
updateViewsAndSetListeners();
}
@@ -313,6 +372,7 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
mAddressesView.removeTextChangedListener(mAddressesTextWatcher);
mIntroducerView.setOnCheckedChangeListener(null);
mDevicePaused.setOnCheckedChangeListener(null);
+ mCustomSyncConditionsSwitch.setOnCheckedChangeListener(null);
// Update views
mIdView.setText(mDevice.deviceID);
@@ -322,12 +382,26 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
mIntroducerView.setChecked(mDevice.introducer);
mDevicePaused.setChecked(mDevice.paused);
+ // Update views - custom sync conditions.
+ mCustomSyncConditionsSwitch.setChecked(false);
+ if (mIsCreateMode) {
+ findViewById(R.id.customSyncConditionsContainer).setVisibility(View.GONE);
+ } else {
+ mCustomSyncConditionsSwitch.setChecked(mPreferences.getBoolean(
+ Constants.DYN_PREF_OBJECT_CUSTOM_SYNC_CONDITIONS(Constants.PREF_OBJECT_PREFIX_DEVICE + mDevice.deviceID), false
+ ));
+ }
+ mCustomSyncConditionsSwitch.setEnabled(!mIsCreateMode);
+ mCustomSyncConditionsDescription.setEnabled(mCustomSyncConditionsSwitch.isChecked());
+ mCustomSyncConditionsDialog.setEnabled(mCustomSyncConditionsSwitch.isChecked());
+
// Keep state updated
mIdView.addTextChangedListener(mIdTextWatcher);
mNameView.addTextChangedListener(mNameTextWatcher);
mAddressesView.addTextChangedListener(mAddressesTextWatcher);
mIntroducerView.setOnCheckedChangeListener(mCheckedListener);
mDevicePaused.setOnCheckedChangeListener(mCheckedListener);
+ mCustomSyncConditionsSwitch.setOnCheckedChangeListener(mCheckedListener);
}
@Override
@@ -423,11 +497,34 @@ public class DeviceActivity extends SyncthingActivity implements View.OnClickLis
/**
* Sends the updated device info if in edit mode.
+ * Preconditions: mDeviceNeedsToUpdate == true
*/
private void updateDevice() {
- if (!mIsCreateMode && mDeviceNeedsToUpdate && mDevice != null) {
- getApi().editDevice(mDevice);
+ if (mIsCreateMode) {
+ // If we are about to create this folder, we cannot update via restApi.
+ return;
}
+ if (mDevice == null) {
+ Log.e(TAG, "updateDevice: mDevice == null");
+ return;
+ }
+
+ // Save device specific preferences.
+ Log.v(TAG, "updateDevice: mDevice.deviceID = \'" + mDevice.deviceID + "\'");
+ SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putBoolean(
+ Constants.DYN_PREF_OBJECT_CUSTOM_SYNC_CONDITIONS(Constants.PREF_OBJECT_PREFIX_DEVICE + mDevice.deviceID),
+ mCustomSyncConditionsSwitch.isChecked()
+ );
+ editor.apply();
+
+ // Update device via restApi and send the config to REST endpoint.
+ RestApi restApi = getApi();
+ if (restApi == null) {
+ Log.e(TAG, "updateDevice: restApi == null");
+ return;
+ }
+ restApi.updateDevice(mDevice);
}
private List persistableAddresses(CharSequence userInput) {
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java
index e0738b9b..c101b613 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java
@@ -263,7 +263,6 @@ public class FolderActivity extends SyncthingActivity
/**
* Invoked after user clicked on the {@link mCustomSyncConditionsDialog} label.
*/
- @SuppressLint("InlinedAPI")
private void onCustomSyncConditionsDialogClick() {
startActivityForResult(
SyncConditionsActivity.createIntent(
@@ -367,7 +366,7 @@ public class FolderActivity extends SyncthingActivity
}
/**
- * Save current settings in case we are in create mode and they aren't yet stored in the config.
+ * Register for service state change events.
*/
@Override
public void onServiceConnected() {
@@ -701,11 +700,19 @@ public class FolderActivity extends SyncthingActivity
deviceView.setOnCheckedChangeListener(mCheckedListener);
}
+ /**
+ * Sends the updated folder info if in edit mode.
+ * Preconditions: mFolderNeedsToUpdate == true
+ */
private void updateFolder() {
if (mIsCreateMode) {
// If we are about to create this folder, we cannot update via restApi.
return;
}
+ if (mFolder == null) {
+ Log.e(TAG, "updateFolder: mFolder == null");
+ return;
+ }
// Save folder specific preferences.
Log.v(TAG, "updateFolder: mFolder.id = \'" + mFolder.id + "\'");
@@ -716,18 +723,13 @@ public class FolderActivity extends SyncthingActivity
);
editor.apply();
- // Update folder via restApi.
+ // Update folder via restApi and send the config to REST endpoint.
RestApi restApi = getApi();
- /**
- * RestApi is guaranteed not to be null as {@link onServiceStateChange}
- * immediately finishes this activity if SyncthingService shuts down.
- */
- /*
if (restApi == null) {
Log.e(TAG, "updateFolder: restApi == null");
return;
}
- */
+
// Update ignore list.
String[] ignore = mEditIgnoreListContent.getText().toString().split("\n");
restApi.postFolderIgnoreList(mFolder.id, ignore);
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
index e9ca27bd..9a9e76f0 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
@@ -105,6 +105,7 @@ public class SettingsActivity extends SyncthingActivity {
private CheckBoxPreference mRunOnMobileData;
private CheckBoxPreference mRunOnWifi;
private CheckBoxPreference mRunOnMeteredWifi;
+ private CheckBoxPreference mUseWifiWhitelist;
private WifiSsidPreference mWifiSsidWhitelist;
private CheckBoxPreference mRunInFlightMode;
@@ -173,6 +174,8 @@ public class SettingsActivity extends SyncthingActivity {
(CheckBoxPreference) findPreference(Constants.PREF_RUN_ON_WIFI);
mRunOnMeteredWifi =
(CheckBoxPreference) findPreference(Constants.PREF_RUN_ON_METERED_WIFI);
+ mUseWifiWhitelist =
+ (CheckBoxPreference) findPreference(Constants.PREF_USE_WIFI_SSID_WHITELIST);
mWifiSsidWhitelist =
(WifiSsidPreference) findPreference(Constants.PREF_WIFI_SSID_WHITELIST);
mRunInFlightMode =
@@ -225,7 +228,8 @@ public class SettingsActivity extends SyncthingActivity {
Preference appVersion = screen.findPreference("app_version");
mRunOnMeteredWifi.setEnabled(mRunOnWifi.isChecked());
- mWifiSsidWhitelist.setEnabled(mRunOnWifi.isChecked());
+ mUseWifiWhitelist.setEnabled(mRunOnWifi.isChecked());
+ mWifiSsidWhitelist.setEnabled(mRunOnWifi.isChecked() && mUseWifiWhitelist.isChecked());
/* Experimental options */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/* Wakelocks are only valid on Android 5 or lower. */
@@ -262,7 +266,7 @@ public class SettingsActivity extends SyncthingActivity {
screen.findPreference(Constants.PREF_POWER_SOURCE).setSummary(mPowerSource.getEntry());
String wifiSsidSummary = TextUtils.join(", ", mPreferences.getStringSet(Constants.PREF_WIFI_SSID_WHITELIST, new HashSet<>()));
screen.findPreference(Constants.PREF_WIFI_SSID_WHITELIST).setSummary(TextUtils.isEmpty(wifiSsidSummary) ?
- getString(R.string.run_on_all_wifi_networks) :
+ getString(R.string.wifi_ssid_whitelist_empty) :
getString(R.string.run_on_whitelisted_wifi_networks, wifiSsidSummary)
);
handleSocksProxyPreferenceChange(screen.findPreference(Constants.PREF_SOCKS_PROXY_ADDRESS), mPreferences.getString(Constants.PREF_SOCKS_PROXY_ADDRESS, ""));
@@ -366,12 +370,16 @@ public class SettingsActivity extends SyncthingActivity {
break;
case Constants.PREF_RUN_ON_WIFI:
mRunOnMeteredWifi.setEnabled((Boolean) o);
+ mUseWifiWhitelist.setEnabled((Boolean) o);
+ mWifiSsidWhitelist.setEnabled((Boolean) o && mUseWifiWhitelist.isChecked());
+ break;
+ case Constants.PREF_USE_WIFI_SSID_WHITELIST:
mWifiSsidWhitelist.setEnabled((Boolean) o);
break;
case Constants.PREF_WIFI_SSID_WHITELIST:
String wifiSsidSummary = TextUtils.join(", ", (Set) o);
preference.setSummary(TextUtils.isEmpty(wifiSsidSummary) ?
- getString(R.string.run_on_all_wifi_networks) :
+ getString(R.string.wifi_ssid_whitelist_empty) :
getString(R.string.run_on_whitelisted_wifi_networks, wifiSsidSummary)
);
break;
@@ -386,7 +394,7 @@ public class SettingsActivity extends SyncthingActivity {
case "deviceName":
Device localDevice = mRestApi.getLocalDevice();
localDevice.name = (String) o;
- mRestApi.editDevice(localDevice);
+ mRestApi.updateDevice(localDevice);
break;
case "listenAddresses":
mOptions.listenAddresses = Iterables.toArray(splitter.split((String) o), String.class);
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/activities/SyncConditionsActivity.java b/app/src/main/java/com/nutomic/syncthingandroid/activities/SyncConditionsActivity.java
index 8c11f9b5..cd5c8d9b 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/activities/SyncConditionsActivity.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/SyncConditionsActivity.java
@@ -60,7 +60,8 @@ public class SyncConditionsActivity extends SyncthingActivity
private SwitchCompat mSyncOnMobileData;
/**
- * Shared preferences names for custom per-folder settings.
+ * Shared preferences names for custom object settings.
+ * Object can e.g. be a folder or device.
*/
private String mObjectPrefixAndId;
private String mPrefSyncOnWifi;
@@ -108,7 +109,7 @@ public class SyncConditionsActivity extends SyncthingActivity
mObjectPrefixAndId = intent.getStringExtra(EXTRA_OBJECT_PREFIX_AND_ID);
Log.v(TAG, "Prefix is \'" + mObjectPrefixAndId + "\' (" + mObjectReadableName + ")");
mPrefSyncOnWifi = Constants.DYN_PREF_OBJECT_SYNC_ON_WIFI(mObjectPrefixAndId);
- mPrefSyncOnWhitelistedWifi = Constants.DYN_PREF_OBJECT_SYNC_ON_WHITELISTED_WIFI(mObjectPrefixAndId);
+ mPrefSyncOnWhitelistedWifi = Constants.DYN_PREF_OBJECT_USE_WIFI_SSID_WHITELIST(mObjectPrefixAndId);
mPrefSelectedWhitelistSsid = Constants.DYN_PREF_OBJECT_SELECTED_WHITELIST_SSID(mObjectPrefixAndId);
mPrefSyncOnMeteredWifi = Constants.DYN_PREF_OBJECT_SYNC_ON_METERED_WIFI(mObjectPrefixAndId);
mPrefSyncOnMobileData = Constants.DYN_PREF_OBJECT_SYNC_ON_MOBILE_DATA(mObjectPrefixAndId);
@@ -117,14 +118,13 @@ public class SyncConditionsActivity extends SyncthingActivity
* Load global run conditions.
*/
Boolean globalRunOnWifiEnabled = mPreferences.getBoolean(Constants.PREF_RUN_ON_WIFI, true);
- Boolean globalWhitelistEnabled = !mPreferences.getStringSet(Constants.PREF_WIFI_SSID_WHITELIST, new HashSet<>())
- .isEmpty();
Set globalWhitelistedSsid = mPreferences.getStringSet(Constants.PREF_WIFI_SSID_WHITELIST, new HashSet<>());
+ Boolean globalWhitelistEnabled = mPreferences.getBoolean(Constants.PREF_USE_WIFI_SSID_WHITELIST, false);
Boolean globalRunOnMeteredWifiEnabled = mPreferences.getBoolean(Constants.PREF_RUN_ON_METERED_WIFI, false);
Boolean globalRunOnMobileDataEnabled = mPreferences.getBoolean(Constants.PREF_RUN_ON_MOBILE_DATA, false);
/**
- * Load custom folder preferences. If unset, use global setting as default.
+ * Load custom object preferences. If unset, use global setting as default.
*/
mSyncOnWifi.setChecked(globalRunOnWifiEnabled && mPreferences.getBoolean(mPrefSyncOnWifi, globalRunOnWifiEnabled));
mSyncOnWifi.setEnabled(globalRunOnWifiEnabled);
@@ -143,7 +143,7 @@ public class SyncConditionsActivity extends SyncthingActivity
mSyncOnMobileData.setOnCheckedChangeListener(mCheckedListener);
// Read selected WiFi Ssid whitelist items.
- Set selectedWhitelistedSsid = mPreferences.getStringSet(mPrefSelectedWhitelistSsid, new HashSet<>());
+ Set selectedWhitelistedSsid = mPreferences.getStringSet(mPrefSelectedWhitelistSsid, globalWhitelistedSsid);
// Removes any network that is no longer part of the global WiFi Ssid whitelist.
selectedWhitelistedSsid.retainAll(globalWhitelistedSsid);
@@ -162,7 +162,7 @@ public class SyncConditionsActivity extends SyncthingActivity
setMarginEnd(params, contentInset);
TextView emptyView = new TextView(mWifiSsidContainer.getContext());
emptyView.setGravity(CENTER_VERTICAL);
- emptyView.setText(R.string.wifi_ssid_whitelist_empty);
+ emptyView.setText(R.string.custom_wifi_ssid_whitelist_empty);
mWifiSsidContainer.addView(emptyView, params);
mWifiSsidContainer.setEnabled(false);
} else {
@@ -224,7 +224,7 @@ public class SyncConditionsActivity extends SyncthingActivity
if (mUnsavedChanges) {
Log.v(TAG, "onPause: mUnsavedChanges == true. Saving prefs ...");
/**
- * Save custom folder preferences.
+ * Save custom object preferences.
*/
SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(mPrefSyncOnWifi, mSyncOnWifi.isChecked());
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
index 10d2a86e..d2a64d80 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
@@ -15,6 +15,7 @@ public class Constants {
public static final String PREF_RUN_ON_MOBILE_DATA = "run_on_mobile_data";
public static final String PREF_RUN_ON_WIFI = "run_on_wifi";
public static final String PREF_RUN_ON_METERED_WIFI = "run_on_metered_wifi";
+ public static final String PREF_USE_WIFI_SSID_WHITELIST = "use_wifi_whitelist";
public static final String PREF_WIFI_SSID_WHITELIST = "wifi_ssid_whitelist";
public static final String PREF_POWER_SOURCE = "power_source";
public static final String PREF_RESPECT_BATTERY_SAVING = "respect_battery_saving";
@@ -43,8 +44,8 @@ public class Constants {
return objectPrefixAndId + "_" + PREF_RUN_ON_WIFI;
}
- public static String DYN_PREF_OBJECT_SYNC_ON_WHITELISTED_WIFI(String objectPrefixAndId) {
- return objectPrefixAndId + "_" + "use_wifi_whitelist";
+ public static String DYN_PREF_OBJECT_USE_WIFI_SSID_WHITELIST(String objectPrefixAndId) {
+ return objectPrefixAndId + "_" + PREF_USE_WIFI_SSID_WHITELIST;
}
public static String DYN_PREF_OBJECT_SELECTED_WHITELIST_SSID(String objectPrefixAndId) {
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java
index afab4c44..74fdecfc 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java
@@ -518,7 +518,7 @@ public class RestApi {
}, errorListener);
}
- public void editDevice(Device newDevice) {
+ public void updateDevice(Device newDevice) {
synchronized (mConfigLock) {
removeDeviceInternal(newDevice.deviceID);
mConfig.devices.add(newDevice);
@@ -782,26 +782,58 @@ public class RestApi {
Log.v(TAG, "onSyncPreconditionChanged: Event fired.");
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
synchronized (mConfigLock) {
- if (mConfig == null || mConfig.folders == null) {
+ Boolean configChanged = false;
+
+ // Check if the config has been loaded.
+ if (mConfig == null) {
+ Log.d(TAG, "onSyncPreconditionChanged: mConfig is not ready yet.");
+ return;
+ }
+
+ // Check if the folders are available from config.
+ if (mConfig.folders != null) {
+ for (Folder folder : mConfig.folders) {
+ Boolean folderCustomSyncConditionsEnabled = sharedPreferences.getBoolean(
+ Constants.DYN_PREF_OBJECT_CUSTOM_SYNC_CONDITIONS(Constants.PREF_OBJECT_PREFIX_FOLDER + folder.id), false
+ );
+ if (folderCustomSyncConditionsEnabled) {
+ Boolean syncConditionsMet = runConditionMonitor.checkObjectSyncConditions(
+ Constants.PREF_OBJECT_PREFIX_FOLDER + folder.id
+ );
+ Log.v(TAG, "onSyncPreconditionChanged: syncFolder(" + folder.id + ")=" + (syncConditionsMet ? "1" : "0"));
+ if (folder.paused != !syncConditionsMet) {
+ folder.paused = !syncConditionsMet;
+ configChanged = true;
+ }
+ }
+ }
+ } else {
Log.d(TAG, "onSyncPreconditionChanged: mConfig.folders is not ready yet.");
return;
}
- Boolean configChanged = false;
- for (Folder folder : mConfig.folders) {
- Boolean folderCustomSyncConditionsEnabled = sharedPreferences.getBoolean(
- Constants.DYN_PREF_OBJECT_CUSTOM_SYNC_CONDITIONS(Constants.PREF_OBJECT_PREFIX_FOLDER + folder.id), false
- );
- if (folderCustomSyncConditionsEnabled) {
- Boolean syncConditionsMet = runConditionMonitor.checkObjectSyncConditions(
- Constants.PREF_OBJECT_PREFIX_FOLDER + folder.id
+
+ // Check if the devices are available from config.
+ if (mConfig.devices != null) {
+ for (Device device : mConfig.devices) {
+ Boolean deviceCustomSyncConditionsEnabled = sharedPreferences.getBoolean(
+ Constants.DYN_PREF_OBJECT_CUSTOM_SYNC_CONDITIONS(Constants.PREF_OBJECT_PREFIX_DEVICE + device.deviceID), false
);
- Log.v(TAG, "onSyncPreconditionChanged: syncFolder(" + folder.id + ")=" + (syncConditionsMet ? "1" : "0"));
- if (folder.paused != !syncConditionsMet) {
- folder.paused = !syncConditionsMet;
- configChanged = true;
+ if (deviceCustomSyncConditionsEnabled) {
+ Boolean syncConditionsMet = runConditionMonitor.checkObjectSyncConditions(
+ Constants.PREF_OBJECT_PREFIX_DEVICE + device.deviceID
+ );
+ Log.v(TAG, "onSyncPreconditionChanged: syncDevice(" + device.deviceID + ")=" + (syncConditionsMet ? "1" : "0"));
+ if (device.paused != !syncConditionsMet) {
+ device.paused = !syncConditionsMet;
+ configChanged = true;
+ }
}
}
+ } else {
+ Log.d(TAG, "onSyncPreconditionChanged: mConfig.devices is not ready yet.");
+ return;
}
+
if (configChanged) {
Log.v(TAG, "onSyncPreconditionChanged: Sending changed config ...");
sendConfig();
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java b/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java
index 5677e5cf..ac08b6fc 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RunConditionMonitor.java
@@ -228,11 +228,13 @@ public class RunConditionMonitor {
/**
* Constants.PREF_WIFI_SSID_WHITELIST
*/
- private SyncConditionResult checkConditionSyncOnWhitelistedWifi(String prefNameSyncOnWhitelistedWifi) {
- Set whitelistedWifiSsids = mPreferences.getStringSet(prefNameSyncOnWhitelistedWifi, new HashSet<>());
- boolean prefWifiWhitelistEnabled = !whitelistedWifiSsids.isEmpty();
+ private SyncConditionResult checkConditionSyncOnWhitelistedWifi(
+ String prefNameUseWifiWhitelist,
+ String prefNameSelectedWhitelistSsid) {
+ boolean wifiWhitelistEnabled = mPreferences.getBoolean(prefNameUseWifiWhitelist, false);
+ Set whitelistedWifiSsids = mPreferences.getStringSet(prefNameSelectedWhitelistSsid, new HashSet<>());
try {
- if (wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
+ if (wifiWhitelistConditionMet(wifiWhitelistEnabled, whitelistedWifiSsids)) {
return new SyncConditionResult(true, "\n" + res.getString(R.string.reason_on_whitelisted_wifi));
}
return new SyncConditionResult(false, "\n" + res.getString(R.string.reason_not_on_whitelisted_wifi));
@@ -348,7 +350,7 @@ public class RunConditionMonitor {
// Wifi type is allowed.
Log.v(TAG, "decideShouldRun: checkConditionSyncOnWifi && checkConditionSyncOnMeteredWifi");
- scr = checkConditionSyncOnWhitelistedWifi(Constants.PREF_WIFI_SSID_WHITELIST);
+ scr = checkConditionSyncOnWhitelistedWifi(Constants.PREF_USE_WIFI_SSID_WHITELIST, Constants.PREF_WIFI_SSID_WHITELIST);
mRunDecisionExplanation += scr.explanation;
if (scr.conditionMet) {
// Wifi is whitelisted.
@@ -395,7 +397,10 @@ public class RunConditionMonitor {
// Wifi type is allowed.
Log.v(TAG, "checkObjectSyncConditions: checkConditionSyncOnWifi && checkConditionSyncOnMeteredWifi");
- scr = checkConditionSyncOnWhitelistedWifi(Constants.DYN_PREF_OBJECT_SELECTED_WHITELIST_SSID(objectPrefixAndId));
+ scr = checkConditionSyncOnWhitelistedWifi(
+ Constants.DYN_PREF_OBJECT_USE_WIFI_SSID_WHITELIST(objectPrefixAndId),
+ Constants.DYN_PREF_OBJECT_SELECTED_WHITELIST_SSID(objectPrefixAndId)
+ );
if (scr.conditionMet) {
// Wifi is whitelisted.
Log.v(TAG, "checkObjectSyncConditions: checkConditionSyncOnWifi && checkConditionSyncOnMeteredWifi && checkConditionSyncOnWhitelistedWifi");
diff --git a/app/src/main/play/en-GB/whatsnew b/app/src/main/play/en-GB/whatsnew
index 24661d4a..51fb0ded 100644
--- a/app/src/main/play/en-GB/whatsnew
+++ b/app/src/main/play/en-GB/whatsnew
@@ -1,5 +1,5 @@
Enhancements
-* Specify sync conditions differently for each folder [NEW]
+* Specify sync conditions differently for each folder, device [NEW]
* UI explains why syncthing is running (or not)
* Support in-app editing of folder's ignore list items
Fixes
diff --git a/app/src/main/res/layout/fragment_device.xml b/app/src/main/res/layout/fragment_device.xml
index 28574c79..17da098b 100644
--- a/app/src/main/res/layout/fragment_device.xml
+++ b/app/src/main/res/layout/fragment_device.xml
@@ -122,6 +122,59 @@
android:drawableStart="@drawable/ic_pause_circle_outline_black_24dp"
android:text="@string/pause_device" />
+
+
+
+
+
+
+
+
+
+
+
+
+
Run when device is connected to a metered Wi-Fi network e.g. a hotspot or tethered network. Attention: This can consume large portion of your data plan if you sync a lot of data.
Run on specified Wi-Fi networks
- Run only on selected Wi-Fi networks: %1$s
+ Select Wi-Fi networks
+ Selected Wi-Fi networks: %1$s
Run on all Wi-Fi networks.
+ No Wi-Fi networks specified. Click to specify networks.
Please turn on Wi-Fi to select networks.
@@ -627,7 +629,7 @@ Please report any problems you encounter via Github.
- No WiFi SSID\'s whitelisted. Please specify some in the settings.
+ No WiFi SSID\'s whitelisted. Please specify some in the settings.
diff --git a/app/src/main/res/xml/app_settings.xml b/app/src/main/res/xml/app_settings.xml
index 0ce25afa..979472d1 100644
--- a/app/src/main/res/xml/app_settings.xml
+++ b/app/src/main/res/xml/app_settings.xml
@@ -12,23 +12,34 @@
android:title="@string/run_conditions_title"
android:summary="@string/run_conditions_summary"/>
+
+
+
+
+
+
+