From 55915d79561d1ef111241273c40d768ba1fef63b Mon Sep 17 00:00:00 2001 From: Catfriend1 Date: Sat, 15 Sep 2018 20:16:20 +0200 Subject: [PATCH] Fix crash when ignoring devices or folders (fixes #50) (#52) --- .../syncthingandroid/model/Config.java | 4 +- .../syncthingandroid/model/Device.java | 2 + .../model/FolderIgnoreList.java | 10 ++ .../syncthingandroid/model/IgnoredFolder.java | 18 ++++ .../syncthingandroid/model/PendingDevice.java | 19 ++++ .../syncthingandroid/model/PendingFolder.java | 18 ++++ .../model/RemoteIgnoredDevice.java | 19 ++++ .../service/EventProcessor.java | 1 + .../syncthingandroid/service/RestApi.java | 98 ++++++++++++++++--- .../service/SyncthingService.java | 2 +- 10 files changed, 176 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/model/FolderIgnoreList.java create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/model/IgnoredFolder.java create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/model/PendingDevice.java create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/model/PendingFolder.java create mode 100644 app/src/main/java/com/nutomic/syncthingandroid/model/RemoteIgnoredDevice.java diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/Config.java b/app/src/main/java/com/nutomic/syncthingandroid/model/Config.java index d9195dfe..fb6581fa 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/model/Config.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/Config.java @@ -8,8 +8,8 @@ public class Config { public List folders; public Gui gui; public Options options; - public List ignoredFolders; - public List ignoredDevices; + public List pendingDevices; + public List remoteIgnoredDevices; public class Gui { public boolean enabled; diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/Device.java b/app/src/main/java/com/nutomic/syncthingandroid/model/Device.java index 01c57b38..29a307fd 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/model/Device.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/Device.java @@ -12,6 +12,8 @@ public class Device { public String certName; public boolean introducer; public boolean paused; + public List pendingFolders; + public List ignoredFolders; /** * Returns the device name, or the first characters of the ID if the name is empty. diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/FolderIgnoreList.java b/app/src/main/java/com/nutomic/syncthingandroid/model/FolderIgnoreList.java new file mode 100644 index 00000000..26811823 --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/FolderIgnoreList.java @@ -0,0 +1,10 @@ +package com.nutomic.syncthingandroid.model; + +/** + * To avoid name confusion: + * This is the exclude and include items list associated with every folder. + */ +public class FolderIgnoreList { + public String[] expanded; + public String[] ignore; +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/IgnoredFolder.java b/app/src/main/java/com/nutomic/syncthingandroid/model/IgnoredFolder.java new file mode 100644 index 00000000..01264c2f --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/IgnoredFolder.java @@ -0,0 +1,18 @@ +package com.nutomic.syncthingandroid.model; + +import android.text.TextUtils; + +public class IgnoredFolder { + public String time = ""; + public String id = ""; + public String label = ""; + + /** + * Returns the folder label, or the first characters of the ID if the label is empty. + */ + public String getDisplayLabel() { + return (TextUtils.isEmpty(label)) + ? id.substring(0, 7) + : label; + } +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/PendingDevice.java b/app/src/main/java/com/nutomic/syncthingandroid/model/PendingDevice.java new file mode 100644 index 00000000..303c8e75 --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/PendingDevice.java @@ -0,0 +1,19 @@ +package com.nutomic.syncthingandroid.model; + +import android.text.TextUtils; + +public class PendingDevice { + public String time = ""; + public String deviceID = ""; + public String name = ""; + public String address = ""; + + /** + * Returns the device name, or the first characters of the ID if the name is empty. + */ + public String getDisplayName() { + return (TextUtils.isEmpty(name)) + ? deviceID.substring(0, 7) + : name; + } +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/PendingFolder.java b/app/src/main/java/com/nutomic/syncthingandroid/model/PendingFolder.java new file mode 100644 index 00000000..b179dbb0 --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/PendingFolder.java @@ -0,0 +1,18 @@ +package com.nutomic.syncthingandroid.model; + +import android.text.TextUtils; + +public class PendingFolder { + public String time = ""; + public String id = ""; + public String label = ""; + + /** + * Returns the folder label, or the first characters of the ID if the label is empty. + */ + public String getDisplayLabel() { + return (TextUtils.isEmpty(label)) + ? id.substring(0, 7) + : label; + } +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/RemoteIgnoredDevice.java b/app/src/main/java/com/nutomic/syncthingandroid/model/RemoteIgnoredDevice.java new file mode 100644 index 00000000..14e16777 --- /dev/null +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/RemoteIgnoredDevice.java @@ -0,0 +1,19 @@ +package com.nutomic.syncthingandroid.model; + +import android.text.TextUtils; + +public class RemoteIgnoredDevice { + public String time = ""; + public String deviceID = ""; + public String name = ""; + public String address = ""; + + /** + * Returns the device name, or the first characters of the ID if the name is empty. + */ + public String getDisplayName() { + return (TextUtils.isEmpty(name)) + ? deviceID.substring(0, 7) + : name; + } +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java b/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java index 05b75fcb..0eb3eefc 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/EventProcessor.java @@ -275,6 +275,7 @@ public class EventProcessor implements Runnable, RestApi.OnReceiveEventListener // Prepare "ignore" action. Intent intentIgnore = new Intent(mContext, SyncthingService.class) .putExtra(SyncthingService.EXTRA_NOTIFICATION_ID, notificationId) + .putExtra(SyncthingService.EXTRA_DEVICE_ID, deviceId) .putExtra(SyncthingService.EXTRA_FOLDER_ID, folderId); intentIgnore.setAction(SyncthingService.ACTION_IGNORE_FOLDER); PendingIntent piIgnore = PendingIntent.getService(mContext, 0, 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 65998bdf..65dba0dd 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java @@ -30,7 +30,11 @@ import com.nutomic.syncthingandroid.model.Device; import com.nutomic.syncthingandroid.model.Event; import com.nutomic.syncthingandroid.model.Folder; import com.nutomic.syncthingandroid.model.FolderStatus; +import com.nutomic.syncthingandroid.model.IgnoredFolder; import com.nutomic.syncthingandroid.model.Options; +import com.nutomic.syncthingandroid.model.PendingDevice; +import com.nutomic.syncthingandroid.model.PendingFolder; +import com.nutomic.syncthingandroid.model.RemoteIgnoredDevice; import com.nutomic.syncthingandroid.model.SystemInfo; import com.nutomic.syncthingandroid.model.SystemVersion; import com.nutomic.syncthingandroid.service.Constants; @@ -213,6 +217,10 @@ public class RestApi { throw new RuntimeException("config is null: " + result); } Log.v(TAG, "onReloadConfigComplete: Successfully parsed configuration."); + if (BuildConfig.DEBUG) { + Log.v(TAG, "mConfig.pendingDevices = " + new Gson().toJson(mConfig.pendingDevices)); + Log.v(TAG, "mConfig.remoteIgnoredDevices = " + new Gson().toJson(mConfig.remoteIgnoredDevices)); + } // Update cached device and folder information stored in the mCompletion model. mCompletion.updateFromConfig(getDevices(true), getFolders()); @@ -259,11 +267,36 @@ public class RestApi { */ public void ignoreDevice(String deviceId) { synchronized (mConfigLock) { - if (!mConfig.ignoredDevices.contains(deviceId)) { - mConfig.ignoredDevices.add(deviceId); - sendConfig(); - Log.d(TAG, "Ignored device [" + deviceId + "]"); + // Check if the device has already been ignored. + for (RemoteIgnoredDevice remoteIgnoredDevice : mConfig.remoteIgnoredDevices) { + if (deviceId.equals(remoteIgnoredDevice.deviceID)) { + // Device already ignored. + Log.d(TAG, "Device already ignored [" + deviceId + "]"); + return; + } } + + /** + * Ignore device by moving its corresponding "pendingDevice" entry to + * a newly created "remotePendingDevice" entry. + */ + RemoteIgnoredDevice remoteIgnoredDevice = new RemoteIgnoredDevice(); + remoteIgnoredDevice.deviceID = deviceId; + Iterator it = mConfig.pendingDevices.iterator(); + while (it.hasNext()) { + PendingDevice pendingDevice = it.next(); + if (deviceId.equals(pendingDevice.deviceID)) { + // Move over information stored in the "pendingDevice" entry. + remoteIgnoredDevice.address = pendingDevice.address; + remoteIgnoredDevice.name = pendingDevice.name; + remoteIgnoredDevice.time = pendingDevice.time; + it.remove(); + break; + } + } + mConfig.remoteIgnoredDevices.add(remoteIgnoredDevice); + sendConfig(); + Log.d(TAG, "Ignored device [" + deviceId + "]"); } } @@ -272,12 +305,49 @@ public class RestApi { * Ignored folders will not trigger the "FolderRejected" event * in {@link EventProcessor#onEvent}. */ - public void ignoreFolder(String folderId) { + public void ignoreFolder(String deviceId, String folderId) { synchronized (mConfigLock) { - if (!mConfig.ignoredFolders.contains(folderId)) { - mConfig.ignoredFolders.add(folderId); - sendConfig(); - Log.d(TAG, "Ignored folder [" + folderId + "]"); + for (Device device : mConfig.devices) { + if (deviceId.equals(device.deviceID)) { + /** + * Check if the folder has already been ignored. + */ + for (IgnoredFolder ignoredFolder : device.ignoredFolders) { + if (folderId.equals(ignoredFolder.id)) { + // Folder already ignored. + Log.d(TAG, "Folder [" + folderId + "] already ignored on device [" + deviceId + "]"); + return; + } + } + + /** + * Ignore folder by moving its corresponding "pendingFolder" entry to + * a newly created "ignoredFolder" entry. + */ + IgnoredFolder ignoredFolder = new IgnoredFolder(); + ignoredFolder.id = folderId; + Iterator it = device.pendingFolders.iterator(); + while (it.hasNext()) { + PendingFolder pendingFolder = it.next(); + if (folderId.equals(pendingFolder.id)) { + // Move over information stored in the "pendingFolder" entry. + ignoredFolder.label = pendingFolder.label; + ignoredFolder.time = pendingFolder.time; + it.remove(); + break; + } + } + device.ignoredFolders.add(ignoredFolder); + if (BuildConfig.DEBUG) { + Log.v(TAG, "device.pendingFolders = " + new Gson().toJson(device.pendingFolders)); + Log.v(TAG, "device.ignoredFolders = " + new Gson().toJson(device.ignoredFolders)); + } + sendConfig(); + Log.d(TAG, "Ignored folder [" + folderId + "] announced by device [" + deviceId + "]"); + + // Given deviceId handled. + break; + } } } } @@ -288,8 +358,10 @@ public class RestApi { public void undoIgnoredDevicesAndFolders() { Log.d(TAG, "Undo ignoring devices and folders ..."); synchronized (mConfigLock) { - mConfig.ignoredDevices.clear(); - mConfig.ignoredFolders.clear(); + mConfig.remoteIgnoredDevices.clear(); + for (Device device : mConfig.devices) { + device.ignoredFolders.clear(); + } } } @@ -413,8 +485,10 @@ public class RestApi { while (it.hasNext()) { Device device = it.next(); boolean isLocalDevice = Objects.equal(mLocalDeviceId, device.deviceID); - if (!includeLocal && isLocalDevice) + if (!includeLocal && isLocalDevice) { it.remove(); + break; + } } return devices; } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java index 53ea6da4..e7928c6b 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java @@ -244,7 +244,7 @@ public class SyncthingService extends Service { mNotificationHandler.cancelConsentNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, 0)); } else if (ACTION_IGNORE_FOLDER.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { // mApi is not null due to State.ACTIVE - mApi.ignoreFolder(intent.getStringExtra(EXTRA_FOLDER_ID)); + mApi.ignoreFolder(intent.getStringExtra(EXTRA_DEVICE_ID), intent.getStringExtra(EXTRA_FOLDER_ID)); mNotificationHandler.cancelConsentNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, 0)); } else if (ACTION_OVERRIDE_CHANGES.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { mApi.overrideChanges(intent.getStringExtra(EXTRA_FOLDER_ID));