1
0
Fork 0
mirror of https://github.com/syncthing/syncthing-android.git synced 2024-12-23 11:21:29 +00:00

Fix crash when ignoring devices or folders (fixes #50) (#52)

This commit is contained in:
Catfriend1 2018-09-15 20:16:20 +02:00 committed by Audrius Butkevicius
parent 34faf02e3c
commit 55915d7956
10 changed files with 176 additions and 15 deletions

View file

@ -8,8 +8,8 @@ public class Config {
public List<Folder> folders; public List<Folder> folders;
public Gui gui; public Gui gui;
public Options options; public Options options;
public List<String> ignoredFolders; public List<PendingDevice> pendingDevices;
public List<String> ignoredDevices; public List<RemoteIgnoredDevice> remoteIgnoredDevices;
public class Gui { public class Gui {
public boolean enabled; public boolean enabled;

View file

@ -12,6 +12,8 @@ public class Device {
public String certName; public String certName;
public boolean introducer; public boolean introducer;
public boolean paused; public boolean paused;
public List<PendingFolder> pendingFolders;
public List<IgnoredFolder> ignoredFolders;
/** /**
* Returns the device name, or the first characters of the ID if the name is empty. * Returns the device name, or the first characters of the ID if the name is empty.

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -275,6 +275,7 @@ public class EventProcessor implements Runnable, RestApi.OnReceiveEventListener
// Prepare "ignore" action. // Prepare "ignore" action.
Intent intentIgnore = new Intent(mContext, SyncthingService.class) Intent intentIgnore = new Intent(mContext, SyncthingService.class)
.putExtra(SyncthingService.EXTRA_NOTIFICATION_ID, notificationId) .putExtra(SyncthingService.EXTRA_NOTIFICATION_ID, notificationId)
.putExtra(SyncthingService.EXTRA_DEVICE_ID, deviceId)
.putExtra(SyncthingService.EXTRA_FOLDER_ID, folderId); .putExtra(SyncthingService.EXTRA_FOLDER_ID, folderId);
intentIgnore.setAction(SyncthingService.ACTION_IGNORE_FOLDER); intentIgnore.setAction(SyncthingService.ACTION_IGNORE_FOLDER);
PendingIntent piIgnore = PendingIntent.getService(mContext, 0, PendingIntent piIgnore = PendingIntent.getService(mContext, 0,

View file

@ -30,7 +30,11 @@ import com.nutomic.syncthingandroid.model.Device;
import com.nutomic.syncthingandroid.model.Event; import com.nutomic.syncthingandroid.model.Event;
import com.nutomic.syncthingandroid.model.Folder; import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.model.FolderStatus; import com.nutomic.syncthingandroid.model.FolderStatus;
import com.nutomic.syncthingandroid.model.IgnoredFolder;
import com.nutomic.syncthingandroid.model.Options; 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.SystemInfo;
import com.nutomic.syncthingandroid.model.SystemVersion; import com.nutomic.syncthingandroid.model.SystemVersion;
import com.nutomic.syncthingandroid.service.Constants; import com.nutomic.syncthingandroid.service.Constants;
@ -213,6 +217,10 @@ public class RestApi {
throw new RuntimeException("config is null: " + result); throw new RuntimeException("config is null: " + result);
} }
Log.v(TAG, "onReloadConfigComplete: Successfully parsed configuration."); 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. // Update cached device and folder information stored in the mCompletion model.
mCompletion.updateFromConfig(getDevices(true), getFolders()); mCompletion.updateFromConfig(getDevices(true), getFolders());
@ -259,11 +267,36 @@ public class RestApi {
*/ */
public void ignoreDevice(String deviceId) { public void ignoreDevice(String deviceId) {
synchronized (mConfigLock) { synchronized (mConfigLock) {
if (!mConfig.ignoredDevices.contains(deviceId)) { // Check if the device has already been ignored.
mConfig.ignoredDevices.add(deviceId); for (RemoteIgnoredDevice remoteIgnoredDevice : mConfig.remoteIgnoredDevices) {
sendConfig(); if (deviceId.equals(remoteIgnoredDevice.deviceID)) {
Log.d(TAG, "Ignored device [" + 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<PendingDevice> 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 * Ignored folders will not trigger the "FolderRejected" event
* in {@link EventProcessor#onEvent}. * in {@link EventProcessor#onEvent}.
*/ */
public void ignoreFolder(String folderId) { public void ignoreFolder(String deviceId, String folderId) {
synchronized (mConfigLock) { synchronized (mConfigLock) {
if (!mConfig.ignoredFolders.contains(folderId)) { for (Device device : mConfig.devices) {
mConfig.ignoredFolders.add(folderId); if (deviceId.equals(device.deviceID)) {
sendConfig(); /**
Log.d(TAG, "Ignored folder [" + folderId + "]"); * 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<PendingFolder> 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() { public void undoIgnoredDevicesAndFolders() {
Log.d(TAG, "Undo ignoring devices and folders ..."); Log.d(TAG, "Undo ignoring devices and folders ...");
synchronized (mConfigLock) { synchronized (mConfigLock) {
mConfig.ignoredDevices.clear(); mConfig.remoteIgnoredDevices.clear();
mConfig.ignoredFolders.clear(); for (Device device : mConfig.devices) {
device.ignoredFolders.clear();
}
} }
} }
@ -413,8 +485,10 @@ public class RestApi {
while (it.hasNext()) { while (it.hasNext()) {
Device device = it.next(); Device device = it.next();
boolean isLocalDevice = Objects.equal(mLocalDeviceId, device.deviceID); boolean isLocalDevice = Objects.equal(mLocalDeviceId, device.deviceID);
if (!includeLocal && isLocalDevice) if (!includeLocal && isLocalDevice) {
it.remove(); it.remove();
break;
}
} }
return devices; return devices;
} }

View file

@ -244,7 +244,7 @@ public class SyncthingService extends Service {
mNotificationHandler.cancelConsentNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, 0)); mNotificationHandler.cancelConsentNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, 0));
} else if (ACTION_IGNORE_FOLDER.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { } else if (ACTION_IGNORE_FOLDER.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
// mApi is not null due to 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)); mNotificationHandler.cancelConsentNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, 0));
} else if (ACTION_OVERRIDE_CHANGES.equals(intent.getAction()) && mCurrentState == State.ACTIVE) { } else if (ACTION_OVERRIDE_CHANGES.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
mApi.overrideChanges(intent.getStringExtra(EXTRA_FOLDER_ID)); mApi.overrideChanges(intent.getStringExtra(EXTRA_FOLDER_ID));