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 511f090c..c0c7af56 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/FolderActivity.java @@ -77,6 +77,7 @@ public class FolderActivity extends SyncthingActivity private EditText mIdView; private TextView mPathView; private SwitchCompat mFolderMasterView; + private SwitchCompat mFolderFileWatcher; private ViewGroup mDevicesContainer; private TextView mVersioningDescriptionView; private TextView mVersioningTypeView; @@ -109,6 +110,10 @@ public class FolderActivity extends SyncthingActivity mFolder.type = (isChecked) ? "readonly" : "readwrite"; mFolderNeedsToUpdate = true; break; + case R.id.fileWatcher: + mFolder.fsWatcherEnabled = isChecked; + mFolderNeedsToUpdate = true; + break; case R.id.device_toggle: Device device = (Device) view.getTag(); if (isChecked) { @@ -135,6 +140,7 @@ public class FolderActivity extends SyncthingActivity mIdView = findViewById(R.id.id); mPathView = findViewById(R.id.directoryTextView); mFolderMasterView = findViewById(R.id.master); + mFolderFileWatcher = findViewById(R.id.fileWatcher); mVersioningDescriptionView = findViewById(R.id.versioningDescription); mVersioningTypeView = findViewById(R.id.versioningType); mDevicesContainer = findViewById(R.id.devicesContainer); @@ -309,6 +315,7 @@ public class FolderActivity extends SyncthingActivity mIdView.removeTextChangedListener(mTextWatcher); mPathView.removeTextChangedListener(mTextWatcher); mFolderMasterView.setOnCheckedChangeListener(null); + mFolderFileWatcher.setOnCheckedChangeListener(null); // Update views mLabelView.setText(mFolder.label); @@ -316,6 +323,7 @@ public class FolderActivity extends SyncthingActivity mPathView.setText(mFolder.path); updateVersioningDescription(); mFolderMasterView.setChecked(Objects.equal(mFolder.type, "readonly")); + mFolderFileWatcher.setChecked(mFolder.fsWatcherEnabled); List devicesList = getApi().getDevices(false); mDevicesContainer.removeAllViews(); @@ -332,6 +340,7 @@ public class FolderActivity extends SyncthingActivity mIdView.addTextChangedListener(mTextWatcher); mPathView.addTextChangedListener(mTextWatcher); mFolderMasterView.setOnCheckedChangeListener(mCheckedListener); + mFolderFileWatcher.setOnCheckedChangeListener(mCheckedListener); } @Override @@ -423,13 +432,13 @@ public class FolderActivity extends SyncthingActivity : generateRandomFolderId(); mFolder.label = getIntent().getStringExtra(EXTRA_FOLDER_LABEL); if (Build.VERSION.SDK_INT != Build.VERSION_CODES.M) { - // Scan every 3 days (in case inotify dropped some changes) - mFolder.rescanIntervalS = 259200; + // Scan every hour (in case real time change detection failed) + mFolder.rescanIntervalS = 3600; } else { // FileObserver is broken on Marshmallow. // https://github.com/syncthing/syncthing-android/issues/787 - mFolder.rescanIntervalS = 60; + mFolder.rescanIntervalS = 300; } mFolder.versioning = new Folder.Versioning(); } 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 eafca03f..a3ce75ff 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java @@ -102,6 +102,7 @@ public class SettingsActivity extends SyncthingActivity { private CheckBoxPreference mRelaysEnabled; private EditTextPreference mGlobalAnnounceServers; private EditTextPreference mAddress; + private CheckBoxPreference mRestartOnWakeup; private CheckBoxPreference mUrAccepted; private Preference mCategoryBackup; @@ -177,6 +178,7 @@ public class SettingsActivity extends SyncthingActivity { mRelaysEnabled = (CheckBoxPreference) findPreference("relaysEnabled"); mGlobalAnnounceServers = (EditTextPreference) findPreference("globalAnnounceServers"); mAddress = (EditTextPreference) findPreference("address"); + mRestartOnWakeup = (CheckBoxPreference) findPreference("restartOnWakeup"); mUrAccepted = (CheckBoxPreference) findPreference("urAccepted"); mCategoryBackup = findPreference("category_backup"); @@ -188,9 +190,9 @@ public class SettingsActivity extends SyncthingActivity { Preference stResetDatabase = findPreference("st_reset_database"); Preference stResetDeltas = findPreference("st_reset_deltas"); - mUseRoot = (CheckBoxPreference) findPreference(Constants.PREF_USE_ROOT); - Preference useWakelock = findPreference(Constants.PREF_USE_WAKE_LOCK); - Preference useTor = findPreference("use_tor"); + mUseRoot = (CheckBoxPreference) findPreference(Constants.PREF_USE_ROOT); + Preference useWakelock = findPreference(Constants.PREF_USE_WAKE_LOCK); + Preference useTor = findPreference(Constants.PREF_USE_TOR); mSyncthingVersion = findPreference("syncthing_version"); Preference appVersion = screen.findPreference("app_version"); @@ -264,6 +266,7 @@ public class SettingsActivity extends SyncthingActivity { mRelaysEnabled.setChecked(mOptions.relaysEnabled); mGlobalAnnounceServers.setText(joiner.join(mOptions.globalAnnounceServers)); mAddress.setText(mGui.address); + mRestartOnWakeup.setChecked(mOptions.restartOnWakeup); mApi.getSystemInfo(systemInfo -> mUrAccepted.setChecked(mOptions.isUsageReportingAccepted(systemInfo.urVersionMax))); } @@ -296,16 +299,33 @@ public class SettingsActivity extends SyncthingActivity { case "listenAddresses": mOptions.listenAddresses = Iterables.toArray(splitter.split((String) o), String.class); break; - case "maxRecvKbps": mOptions.maxRecvKbps = Integer.parseInt((String) o); break; - case "maxSendKbps": mOptions.maxSendKbps = Integer.parseInt((String) o); break; - case "natEnabled": mOptions.natEnabled = (boolean) o; break; - case "localAnnounceEnabled": mOptions.localAnnounceEnabled = (boolean) o; break; - case "globalAnnounceEnabled": mOptions.globalAnnounceEnabled = (boolean) o; break; - case "relaysEnabled": mOptions.relaysEnabled = (boolean) o; break; + case "maxRecvKbps": + mOptions.maxRecvKbps = Integer.parseInt((String) o); + break; + case "maxSendKbps": + mOptions.maxSendKbps = Integer.parseInt((String) o); + break; + case "natEnabled": + mOptions.natEnabled = (boolean) o; + break; + case "localAnnounceEnabled": + mOptions.localAnnounceEnabled = (boolean) o; + break; + case "globalAnnounceEnabled": + mOptions.globalAnnounceEnabled = (boolean) o; + break; + case "relaysEnabled": + mOptions.relaysEnabled = (boolean) o; + break; case "globalAnnounceServers": mOptions.globalAnnounceServers = Iterables.toArray(splitter.split((String) o), String.class); break; - case "address": mGui.address = (String) o; break; + case "address": + mGui.address = (String) o; + break; + case "restartOnWakeup": + mOptions.restartOnWakeup = (boolean) o; + break; case "urAccepted": mApi.getSystemInfo(systemInfo -> { mOptions.urAccepted = ((boolean) o) diff --git a/app/src/main/java/com/nutomic/syncthingandroid/model/Folder.java b/app/src/main/java/com/nutomic/syncthingandroid/model/Folder.java index 365c5816..b0a2a572 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/model/Folder.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/model/Folder.java @@ -15,6 +15,8 @@ public class Folder { public String label; public String path; public String type; + public boolean fsWatcherEnabled = true; + public int fsWatcherDelayS = 10; private List devices = new ArrayList<>(); public int rescanIntervalS; public final boolean ignorePerms = true; 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 e602fe59..a2ead0f3 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java @@ -8,14 +8,15 @@ import java.util.concurrent.TimeUnit; public class Constants { - public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background"; - public static final String PREF_SYNC_ONLY_WIFI = "sync_only_wifi"; - public static final String PREF_SYNC_ONLY_WIFI_SSIDS = "sync_only_wifi_ssids_set"; - public static final String PREF_SYNC_ONLY_CHARGING = "sync_only_charging"; - public static final String PREF_RESPECT_BATTERY_SAVING = "respect_battery_saving"; - public static final String PREF_USE_ROOT = "use_root"; - public static final String PREF_NOTIFICATION_TYPE = "notification_type"; - public static final String PREF_USE_WAKE_LOCK = "wakelock_while_binary_running"; + public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background"; + public static final String PREF_SYNC_ONLY_WIFI = "sync_only_wifi"; + public static final String PREF_SYNC_ONLY_WIFI_SSIDS = "sync_only_wifi_ssids_set"; + public static final String PREF_SYNC_ONLY_CHARGING = "sync_only_charging"; + public static final String PREF_RESPECT_BATTERY_SAVING = "respect_battery_saving"; + public static final String PREF_USE_ROOT = "use_root"; + public static final String PREF_NOTIFICATION_TYPE = "notification_type"; + public static final String PREF_USE_WAKE_LOCK = "wakelock_while_binary_running"; + public static final String PREF_USE_TOR = "use_tor"; /** * On Android 8.1, ACCESS_COARSE_LOCATION is required to access WiFi SSID. 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 78864896..a814e3ca 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/RestApi.java @@ -32,7 +32,6 @@ import com.nutomic.syncthingandroid.model.Model; import com.nutomic.syncthingandroid.model.Options; import com.nutomic.syncthingandroid.model.SystemInfo; import com.nutomic.syncthingandroid.model.SystemVersion; -import com.nutomic.syncthingandroid.util.FolderObserver; import java.lang.reflect.Type; import java.net.URL; @@ -49,8 +48,7 @@ import javax.inject.Inject; /** * Provides functions to interact with the syncthing REST API. */ -public class RestApi implements SyncthingService.OnWebGuiAvailableListener, - FolderObserver.OnFolderFileChangeListener { +public class RestApi implements SyncthingService.OnWebGuiAvailableListener { private static final String TAG = "RestApi"; @@ -145,6 +143,7 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener, tryIsAvailable(); }); new GetRequest(mContext, mUrl, GetRequest.URI_CONFIG, mApiKey, null, result -> { + Log.v(TAG, "onWebGuiAvailable: " + result); mConfig = new Gson().fromJson(result, Config.class); if (mConfig == null) { throw new RuntimeException("config is null: " + result); @@ -485,14 +484,6 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener, }); } - /** - * Force a rescan of the given subdirectory in folder. - */ - @Override - public void onFolderFileChange(String folderId, String relativePath) { - new PostScanRequest(mContext, mUrl, mApiKey, folderId, relativePath); - } - /** * Returns prettyfied usage report. */ diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java index 57a43be9..0becf4cc 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingRunnable.java @@ -71,6 +71,8 @@ public class SyncthingRunnable implements Runnable { mContext = context; mSyncthingBinary = Constants.getSyncthingBinary(mContext); mLogFile = Constants.getLogFile(mContext); + + // Get preferences relevant to starting syncthing core. mUseRoot = mPreferences.getBoolean(Constants.PREF_USE_ROOT, false) && Shell.SU.available(); switch (command) { case generate: @@ -371,7 +373,7 @@ public class SyncthingRunnable implements Runnable { // Disable hash benchmark for faster startup. // https://github.com/syncthing/syncthing/issues/4348 targetEnv.put("STHASHING", "minio"); - if (mPreferences.getBoolean("use_tor", false)) { + if (mPreferences.getBoolean(Constants.PREF_USE_TOR, false)) { targetEnv.put("all_proxy", "socks5://localhost:9050"); targetEnv.put("ALL_PROXY_NO_FALLBACK", "1"); } 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 2f520548..5cf9a497 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java @@ -18,7 +18,6 @@ import com.nutomic.syncthingandroid.SyncthingApp; import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask; import com.nutomic.syncthingandroid.model.Folder; import com.nutomic.syncthingandroid.util.ConfigXml; -import com.nutomic.syncthingandroid.util.FolderObserver; import java.io.File; import java.io.IOException; @@ -95,7 +94,6 @@ public class SyncthingService extends Service { private DeviceStateHolder mDeviceStateHolder; private SyncthingRunnable mSyncthingRunnable; - private final LinkedList mObservers = new LinkedList<>(); private final HashSet mOnApiChangeListeners = new HashSet<>(); private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this); @@ -232,22 +230,7 @@ public class SyncthingService extends Service { private void onSyncthingStarted() { onApiChange(State.ACTIVE); - Handler handler = new Handler(); - new Thread(() -> { - for (Folder r : mApi.getFolders()) { - try { - mObservers.add(new FolderObserver(mApi, r, handler)); - } catch (FolderObserver.FolderNotExistingException e) { - Log.w(TAG, "Failed to add observer for folder", e); - } catch (StackOverflowError e) { - Log.w(TAG, "Failed to add folder observer", e); - Toast.makeText(SyncthingService.this, - R.string.toast_folder_observer_stack_overflow, - Toast.LENGTH_LONG) - .show(); - } - } - }).start(); + Log.i(TAG, "onSyncthingStarted(): State.ACTIVE reached."); } @Override @@ -295,9 +278,6 @@ public class SyncthingService extends Service { mNotificationHandler.cancelPersistentNotification(this); - Stream.of(mObservers).forEach(FolderObserver::stopWatching); - mObservers.clear(); - if (mSyncthingRunnable != null) { mSyncthingRunnable.killSyncthing(onKilledListener); mSyncthingRunnable = null; diff --git a/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java b/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java index 4cdc5540..2e1cc6e1 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/util/ConfigXml.java @@ -1,8 +1,10 @@ package com.nutomic.syncthingandroid.util; import android.content.Context; +import android.content.SharedPreferences; import android.os.Build; import android.os.Environment; +import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; @@ -23,6 +25,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; +import javax.inject.Inject; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -45,6 +48,7 @@ public class ConfigXml { private static final String TAG = "ConfigXml"; private final Context mContext; + @Inject SharedPreferences mPreferences; private final File mConfigFile; @@ -62,8 +66,18 @@ public class ConfigXml { readConfig(); if (isFirstStart) { + boolean changed = false; + + /* Synthing devices */ changeLocalDeviceName(); - changeDefaultFolder(); + + /* Syncthing folders */ + changed = changeDefaultFolder() || changed; + + // Save changes if we made any. + if (changed) { + saveChanges(); + } } } @@ -110,9 +124,15 @@ public class ConfigXml { */ @SuppressWarnings("SdCardPath") public void updateIfNeeded() { - Log.i(TAG, "Checking for needed config updates"); boolean changed = false; + + /* Perform one-time migration tasks on syncthing's config file when coming from an older config version. */ + changed = migrateSyncthingOptions() || changed; + + /* Get refs to important config objects */ NodeList folders = mConfig.getDocumentElement().getElementsByTagName("folder"); + + /* Section - folders */ for (int i = 0; i < folders.getLength(); i++) { Element r = (Element) folders.item(i); // Set ignorePerms attribute. @@ -128,6 +148,7 @@ public class ConfigXml { changed = setConfigElement(r, "hashers", "1") || changed; } + /* Section - GUI */ // Enforce TLS. Element gui = getGuiElement(); changed = setConfigElement(gui, "tls", "true") || changed; @@ -156,17 +177,79 @@ public class ConfigXml { changed = true; } + /* Section - options */ // Disable weak hash benchmark for faster startup. // https://github.com/syncthing/syncthing/issues/4348 Element options = (Element) mConfig.getDocumentElement() .getElementsByTagName("options").item(0); changed = setConfigElement(options, "weakHashSelectionMethod", "never") || changed; + /* Dismiss "fsWatcherNotification" according to https://github.com/syncthing/syncthing-android/pull/1051 */ + NodeList childNodes = options.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node.getNodeName().equals("unackedNotificationID")) { + if (node.equals("fsWatcherNotification")) { + Log.i(TAG, "Remove found unackedNotificationID 'fsWatcherNotification'."); + options.removeChild(node); + changed = true; + break; + } + } + } + + // Save changes if we made any. if (changed) { saveChanges(); } } + /** + * Updates syncthing options to a version specific target setting in the config file. + * + * Used for one-time config migration from a lower syncthing version to the current version. + * Enables filesystem watcher. + * Returns if changes to the config have been made. + */ + private boolean migrateSyncthingOptions () { + /* Read existing config version */ + int iConfigVersion = Integer.parseInt(mConfig.getDocumentElement().getAttribute("version")); + int iOldConfigVersion = iConfigVersion; + Log.i(TAG, "Found existing config version " + Integer.toString(iConfigVersion)); + + /* Check if we have to do manual migration from version X to Y */ + if (iConfigVersion == 27) { + /* fsWatcher transition - https://github.com/syncthing/syncthing/issues/4882 */ + Log.i(TAG, "Migrating config version " + Integer.toString(iConfigVersion) + " to 28 ..."); + + /* Enable fsWatcher for all folders */ + NodeList folders = mConfig.getDocumentElement().getElementsByTagName("folder"); + for (int i = 0; i < folders.getLength(); i++) { + Element r = (Element) folders.item(i); + + // Enable "fsWatcherEnabled" attribute and set default delay. + Log.i(TAG, "Set 'fsWatcherEnabled', 'fsWatcherDelayS' on folder " + r.getAttribute("id")); + r.setAttribute("fsWatcherEnabled", "true"); + r.setAttribute("fsWatcherDelayS", "10"); + } + + /** + * Set config version to 28 after manual config migration + * This prevents "unackedNotificationID" getting populated + * with the fsWatcher GUI notification. + */ + iConfigVersion = 28; + } + + if (iConfigVersion != iOldConfigVersion) { + mConfig.getDocumentElement().setAttribute("version", Integer.toString(iConfigVersion)); + Log.i(TAG, "New config version is " + Integer.toString(iConfigVersion)); + return true; + } else { + return false; + } + } + private boolean setConfigElement(Element parent, String tagName, String textContent) { Node element = parent.getElementsByTagName(tagName).item(0); if (element == null) { @@ -203,8 +286,9 @@ public class ConfigXml { /** * Change default folder id to camera and path to camera folder path. + * Returns if changes to the config have been made. */ - private void changeDefaultFolder() { + private boolean changeDefaultFolder() { Element folder = (Element) mConfig.getDocumentElement() .getElementsByTagName("folder").item(0); String model = Build.MODEL @@ -216,7 +300,9 @@ public class ConfigXml { folder.setAttribute("path", Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath()); folder.setAttribute("type", "readonly"); - saveChanges(); + folder.setAttribute("fsWatcherEnabled", "true"); + folder.setAttribute("fsWatcherDelayS", "10"); + return true; } /** diff --git a/app/src/main/java/com/nutomic/syncthingandroid/util/FolderObserver.java b/app/src/main/java/com/nutomic/syncthingandroid/util/FolderObserver.java deleted file mode 100644 index e62406c0..00000000 --- a/app/src/main/java/com/nutomic/syncthingandroid/util/FolderObserver.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.nutomic.syncthingandroid.util; - -import android.os.FileObserver; -import android.os.Handler; -import android.util.Log; - -import com.annimon.stream.Stream; -import com.nutomic.syncthingandroid.model.Folder; - -import java.io.File; -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; - -/** - * Recursively watches a directory and all subfolders. - */ -public class FolderObserver extends FileObserver { - - private static final String TAG = "FolderObserver"; - - private static final long SCAN_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(10); - - private final OnFolderFileChangeListener mListener; - private final Folder mFolder; - private final String mPath; - private final ArrayList mChilds = new ArrayList<>(); - private final Handler mHandler; - - public interface OnFolderFileChangeListener { - void onFolderFileChange(String folderId, String relativePath); - } - - public FolderObserver(OnFolderFileChangeListener listener, Folder folder, Handler mainHandler) - throws FolderNotExistingException { - this(listener, folder, "", mainHandler); - Log.i(TAG, "Observer created for (folder " + folder.id + ")"); - } - - public class FolderNotExistingException extends Exception { - - private final String mPath; - - public FolderNotExistingException(String path) { - mPath = path; - } - - @Override - public String getMessage() { - return "path " + mPath + " does not exist, aborting file observer"; - } - } - - /** - * Constructs watcher and starts watching the given directory recursively. - * - * @param listener The listener where changes should be sent to. - * @param folder The folder where this folder belongs to. - * @param path path to the monitored folder, relative to folder root. - */ - private FolderObserver(OnFolderFileChangeListener listener, Folder folder, String path, Handler handler) - throws FolderNotExistingException { - super(folder.path + "/" + path, - ATTRIB | CLOSE_WRITE | CREATE | DELETE | DELETE_SELF | MOVED_FROM | - MOVED_TO | MOVE_SELF); - mListener = listener; - mFolder = folder; - mPath = path; - mHandler = handler; - Log.v(TAG, "Observer created for " + new File(mFolder.path, mPath).toString() + " (folder " + folder.id + ")"); - startWatching(); - - File currentFolder = new File(folder.path, path); - if (!currentFolder.exists()) { - throw new FolderNotExistingException(currentFolder.getAbsolutePath()); - } - File[] directories = currentFolder.listFiles((current, name) -> new File(current, name).isDirectory()); - - if (directories != null) { - for (File f : directories) { - mChilds.add(new FolderObserver(mListener, mFolder, path + "/" + f.getName(), mHandler)); - } - } - } - - /** - * Handles incoming events for changed files. - */ - @Override - public void onEvent(int event, String path) { - // Ignore some weird events that we may receive. - event &= FileObserver.ALL_EVENTS; - if (event == 0) - return; - - File fullPath = (path != null) - ? new File(mPath, path) - : new File(mPath); - - Log.v(TAG, "Received inotify event " + Integer.toHexString(event) + " at " + - fullPath.getAbsolutePath()); - switch (event) { - case MOVED_FROM: - // fall through - case DELETE_SELF: - // fall through - case DELETE: - for (FolderObserver c : mChilds) { - if (c.mPath.equals(path)) { - mChilds.remove(c); - break; - } - } - mHandler.postDelayed(() -> mListener.onFolderFileChange(mFolder.id, fullPath.getPath()), - SCAN_DELAY_MILLIS); - break; - case MOVED_TO: - // fall through - case CREATE: - if (fullPath.isDirectory()) { - try { - mChilds.add(new FolderObserver(mListener, mFolder, path, mHandler)); - } catch (FolderNotExistingException e) { - Log.w(TAG, "Failed to add listener for nonexisting folder", e); - } - } - // fall through - default: - mHandler.postDelayed(() -> mListener.onFolderFileChange(mFolder.id, fullPath.getPath()), - SCAN_DELAY_MILLIS); - } - } - - /** - * Recursively stops watching the directory. - */ - @Override - public void stopWatching() { - super.stopWatching(); - Stream.of(mChilds).forEach(FolderObserver::stopWatching); - } -} diff --git a/app/src/main/res/layout/fragment_folder.xml b/app/src/main/res/layout/fragment_folder.xml index 8f32a839..bb14b349 100644 --- a/app/src/main/res/layout/fragment_folder.xml +++ b/app/src/main/res/layout/fragment_folder.xml @@ -80,6 +80,16 @@ android:drawableStart="@drawable/ic_lock_black_24dp_active" android:text="@string/folder_master" /> + + Syncthing работи Syncthing не работи - Твърде много папки. Проверяване за cyclic symlinks Камера diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index 53c974a5..b4302362 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -318,7 +318,6 @@ Ens podeu informar dels problemes que trobeu a través de Github. El Syncthing s\'està executant El Syncthing està desactivat - L\'arbre de directoris és massa profund. Comproveu que no hi hagi enllaços simbòlics cíclics No s\'ha pogut crear el fitxer de configuració diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index bd2a78a5..e61e9168 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -321,7 +321,6 @@ Všechny zaznamenané chyby prosím hlašte přes Github. Syncthing běží Syncthing je vypnutý - Adresářová struktura je moc hluboká. Zkontrolujte zacyklené symlinky. Vytváření konfiguračního souboru selhalo diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 560efe5c..4aa59f1a 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -313,7 +313,6 @@ Vær venlig at rapportere ethvert problem, du støder på, via Github. Syncthing kører Syncthing er slået fra - Katalog-tree for dybt. Check for cyclic symlinks Kamera diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 86361281..642f90e5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -317,7 +317,6 @@ Bitte melden Sie auftretende Probleme via Github. Syncthing läuft Syncthing ist deaktiviert - Verzeichnisbaum zu verschachtelt. Auf zyklische symlinks prüfen Erstellen der Konfigurationsdatei fehlgeschalgen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index adc46802..c5cc1c18 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -318,7 +318,6 @@ Το Syncthing εκτελείται Το Syncthing είναι απενεργοποιημένο - Η ιεραρχία των φακέλων έχει υπερβολικά μεγάλο βάθος. Ελέγξτε αν υπάρχουν κυκλικοί συμβολικοί σύνδεσμοι Αδυναμία δημιουργίας αρχείου ρυθμίσεων diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index b93d6d6d..3a1e441d 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -236,7 +236,6 @@ Syncthing está en ejecución Syncthing está deshabilitado - Árbol de carpetas muy profundo. Revise por enlaces simbólicos cíclicos. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c3edc756..5451ff05 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -289,7 +289,6 @@ Syncthing se está ejecutando Syncthing está deshabilitado - Árbol de directorios demasiado profundo. Comprueba enlaces simbólicos cíclicos Cámara diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 7fd2e17d..19902de6 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -278,7 +278,6 @@ Ilmoitathan ystävällisesti kaikista havaitsemistasi ongelmista Githubin kautta Syncthing on käynnissä Syncthing on poistettu käytöstä - Kansiopolku on liian syvä. Tarkista toistuvat symlinkit. Kamera diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 54bd4e8d..578d8c1c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -318,7 +318,6 @@ S\'il vous plaît, soumettez les problèmes que vous rencontrez via Github.Syncthing fonctionne Syncthing est désactivé - Arborescence des répertoires trop profonde. Vérifiez les liens symboliques cycliques. Echec de création du fichier de configuration diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index c899af9e..02aeec03 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -326,7 +326,6 @@ Biztosan törölni szeretnéd a Syncthing index adatbázisát? A Syncthing fut A Syncthing le van tiltva - A mappastruktúra túl mély. Ellenőrizd, nincsenek-e körkörös symlinkek. Nem sikerült létrehozni a konfigurációs fájlt diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 5b1ff046..d56a6013 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -318,7 +318,6 @@ Si prega di segnalare eventuali problemi che si incontrano via Github. Syncthing è in esecuzione Syncthing è disabilitato - Albero delle cartelle troppo nidificato. Verificare la presenza di link simbolici ciclici Impossibile creare il file di configurazione diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 6ca9bd71..8f976421 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -313,7 +313,6 @@ Syncthing は実行中です Syncthing は無効になりました - ディレクトリーの階層が深すぎます。シンボリックリンクの循環を確認してください 設定ファイルの作成に失敗しました diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 2855b92f..e67c5cb5 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -309,7 +309,6 @@ Syncthing이 작동 중입니다 Syncthing이 비활성화되었습니다 - 폴더의 계층이 너무 깊습니다. 심볼릭 링크의 순환을 확인해주세요. 카메라 diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index ea10f587..b3dd262e 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -240,7 +240,6 @@ Syncthing kjører Syncthing er deaktivert - Katalogtreet er for dypt. Se etter sykliske symlenker. Kamera diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index edc9db7b..013b7610 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -317,7 +317,6 @@ Als je problemen tegenkomt, meld ze dan via GitHub. Syncthing draait Syncthing is uitgeschakeld - Mapstructuur te diep. Controleer op cyclische symlinks Aanmaken van configuratiebestand mislukt diff --git a/app/src/main/res/values-nn/strings.xml b/app/src/main/res/values-nn/strings.xml index dd69ac5d..6d1db39b 100644 --- a/app/src/main/res/values-nn/strings.xml +++ b/app/src/main/res/values-nn/strings.xml @@ -240,7 +240,6 @@ Syncthing køyrer Syncthing er ikkje aktivert - Mappetreet er for djupt. Sjekk om det finst sykliske symbolske lenkjer Kamera diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 52214297..ae91a73a 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -270,7 +270,6 @@ Proszę zgłaszać napotkane błędy programu za pośrednictwem serwisu Github.< Syncthing jest uruchomiony Syncthing jest wyłączony - Drzewo katalogów jest zbyt głębokie. Proszę je sprawdzić pod kątem obecności zapętlonych dowiązań symbolicznych. Kamera diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1c32e2e1..fd5ccb4f 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -314,7 +314,6 @@ Por favor, nos avise sobre quaisquer problemas que você encontrar via Github.O Syncthing está rodando O Syncthing está desabilitado - Árvore de diretórios profunda demais. Verifique links simbólicos cíclicos. Não foi possível criar o arquivo de configuração diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index fcf7a70e..738a0fa2 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -262,7 +262,6 @@ Reporte, através do Github, quaisquer problemas que encontre, por favor.O Syncthing está a correr O Syncthing está desactivado - Árvore de pastas demasiado profunda. Verifique se existem ligações simbólicas cíclicas Câmera diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 38392a8e..df874a0c 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -321,7 +321,6 @@ Vă rugăm să raportați orice problemă întâlniți, prin intermediul GitHub. Syncthing rulează Syncthing este dezactivat - Structura directorului este prea complexa. Verificați existența legăturilor simbolice Creerea fișierului de configurare a eșuat diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 68e433ef..3812689b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -274,7 +274,6 @@ Syncthing запущен Syncthing выключен - Слишком глубокая папка. Проверьте на цикличные симлинки Камера diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index c8cdd3eb..bbc070eb 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -222,7 +222,6 @@ Naozaj chcete resetovať databázu s indexom súborov? Syncthing beží Syncthing je zakázaný - Strom adresárov je príliš hlboký. Skontrolujte, či neobsahuje zacyklené symlinky. diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 75c61d18..a9f40668 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -317,7 +317,6 @@ Vänligen rapportera eventuella problem du stöter på via Github. Syncthing körs Syncthing är inaktiverad - Katalogträdet är för djupt. Kontrollera efter cyclic symlinks Misslyckades med att skapa konfigurationsfil diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index a011db52..ca3a9980 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -261,7 +261,6 @@ Eğer herhangi bir sorunla karşılaşırsan Github aracılığıyla bildir.Syncthing çalışıyor Syncthing devre dışı - Dizin ağacı çok derin. Döngüsel simgesel bağlantıların varlığını araştır Kamera diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index b61291d2..3e852548 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -236,7 +236,6 @@ Syncthing đang chạy Đã tắt Syncthing - Cây th.mục quá sâu. Hãy k.tra các l.kết biểu trưng trùng lặp diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d234f9e0..edb43fd7 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -315,7 +315,6 @@ Syncthing 正在运行 Syncthing 已禁用 - 目录树层次过深,正在检查循环符号链接。 创建配置文件失败 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 1d572241..50325baf 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -314,7 +314,6 @@ Syncthing 正在執行 Syncthing 已經停用 - 太深的樹狀資料夾。檢查是否有循環的連結。 無法建立設定檔 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5aa0ec9e..acd1523c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -141,6 +141,9 @@ Please report any problems you encounter via Github. Send Only + + Realtime Sync + Devices @@ -344,6 +347,14 @@ Please report any problems you encounter via Github. Force Syncthing to use legacy hashing package for compatibility purposes + Use deprecated change detection + + Default: Disabled. Use deprecated android implementation to detect filesystem changes instead of SyncThing\'s new built-in feature. + + Restart on Wakeup + + Default: Enabled. Disabling this feature may result in folder scans and device reconnects being delayed to save battery. + Do you really want to export your configuration? Existing files will be overwritten.\n\nWARNING! Other applications may be able to read the private key from the backup location and use it to download/modify synchronized files. @@ -536,9 +547,6 @@ Please report any problems you encounter via Github. Syncthing is disabled - - Directory tree too deep. Check for cyclic symlinks - Failed to create config file diff --git a/app/src/main/res/xml/app_settings.xml b/app/src/main/res/xml/app_settings.xml index 4cab8638..4a870995 100644 --- a/app/src/main/res/xml/app_settings.xml +++ b/app/src/main/res/xml/app_settings.xml @@ -125,6 +125,12 @@ android:persistent="false" android:inputType="textNoSuggestions" /> + +