Option for Android notification when repository updates?

Would it be a difficult task to enable an option in the repository settings in the Android app that would post a system notification when that repo is modified by another node? This simple feature would add tremendous value to the Syncthing app, because currently there is no convenient way for someone sharing a repository with others to know that someone else added or changed a file.

I would love to be able to distribute photos and videos to my family and friends by simply adding them to a shared repository where they would be automatically notified. Or if Iā€™m collaborating on a document, it would be nice to efficiently know when updates are made.

See #130.

So it would be possible to implement, but tbh I donā€™t have the time/motivation at the moment.

Oh, I forgot to search the GitHub issues before posting. Itā€™s still not reading those threads how to implement the feature. Could you sketch some details about the functions that should be modified? I might be able to do it myself if I have some starting guidance.

I just tried to find out, but Iā€™m actually not sure.

@AudriusButkevicius How does completion status give me info about files synced to the device? REST documentation says it only gives a percentage.

It appears that we have a choice either to (1) add the functionality to the Android app itself or (2) add it to Syncthing and create an additional REST API that the app uses to check for changes to the specified repos in order to issue a system notification. It would seem that (2) is the better option since this notification feature would be useful across platforms.

The event interface gives info about files that are updated. You could subscribe to that and do something when an interesting file is changed.

Ah I see.

@anaqreon So youā€™d add a getEvents(int id) to RestApi. That function does the API request and parses the JSON into a new, appropriate Java object (like RestApi.Device).

Then you add functionality to SyncthingService to poll that function and create notifications on change. Also, there should be a setting to enable this (imo it should be off by default).

Please tell me if you need more help :wink:

I think Iā€™ve got a decent handle on the first half of your outline. I have a RestApi.SyncEvent static class that should contain the information in each event returned by the /rest/events API. I created a listener interface class that takes a list of SyncEvent objects and doesā€¦ something. Now I need guidance on how to implement that listener function in SyncthingService.java to actually do something with the information.

Is this Event API something that has to be polled at some fixed frequency (like every 30-60 sec)? Iā€™m guessing that somehow SyncthingService will need a variable that keeps track of the last SyncEvent ID to minimize the data transfer and parsing.

Event API takes some query parameters (I think since=N or last=M) to indicate that you are interested in events older than N or last M events available. If there arenā€™t any events, the call will block up for up to a minute after which it will time out and should be retried.

Exactly, you can do a regular poll with a timer like here. Then you save the last event ID in a member variable and pass it in.

I created a polling function as you suggested and made SyncthingService implement a listener interface class to get the list of recent events. Hereā€™s the latest code. I have minimal experience with Java, so what Iā€™ve done so far needs some detailed review so I donā€™t do something too stupid.

The next step is to analyze the list of returned SyncEvent objects and (1) identify events that mean a new file has been added to a specified repo and (2) issue an Android system notification to the user. Right now I donā€™t have a clue how to do either of those things, so more suggestions are welcome!

I donā€™t think there is a ā€˜A file has been addedā€™ event, but there is ā€˜RemoteIndexChangedā€™ which means that we will start downloading stuff as something has changed on a remote node. You can track files with ā€˜DownloadProgressā€™ event but this might be excessive as itā€™s per file, and given you have 200new files added, that means 200 notifications.

The use case in mind is a repo that doesnā€™t get updates or modifications very often, like the photo sharing example I mentioned. When many files are added, they are typically added at once. Perhaps the plan should be to check very infrequently (5-10 min) so that it is easier to reduce the quantity of notifications by summarizing/compacting a something like 200 new files with a single notification that says ā€œ200 files addedā€.

The code looks good to me. Only thing I would change is inline the SyncthingService#getEvents() function (itā€™s a two-liner thatā€™s only called from one place).

Have you thought about what action the notification should have? I suppose it should show a dialog listing the changed files, maybe with an option to open/view them. Or open the directory/file directly for a single change.

Update: Using the CatLog app I can see that I am indeed retrieving events periodically as the timer fires, so thatā€™s progress! Now itā€™s on to the actual notification mechanism. Iā€™m going to start with something vague and simple like ā€œSomething changed in one of your reposā€. Then weā€™ll need to design a way for the user to (1) toggle the notification feature and (2) specify the repos for which they want notifications.

By the way, when I pull the latest updates from upstream, is there a way to have git automatically checkout the current syncthing subproject tag? I have to manually check the commit history to see that, for example, you bumped it up to v0.10.11.

1 Like

Hereā€™s how to make a notification.

Iā€™m not sure if we need a per-repo setting for notifications, could be too much clutter. For the global preference, you want to edit SettingsFragment and app_settings.xml (have a look at the ALWAYS_RUN_IN_BACKGROUND preference and copy that).

For the submodule, thereā€™s an answer on stackoverflow.

Btw itā€™s probably more convenient to use adb logcat or the logcat view in Android Studio :wink:

Thanks for the links and guidance. I create a simple notification toggle setting that seems like it should work but doesnā€™t. You should check that the method of using the onApiChange() function for stopping and starting the timer that fires the event poller is the sensible thing to do.

I disagree that a global preference like this ā€œfirst draftā€ learning effort is sufficient. Some repos might have frequent updates due to some automated process that the user has no desire to be notified about, while one or two of their other repos are folders shared among friends and family for social networking purposes, in which case they do want the handful of notifications they might receive per day. To implement this, should we add an additional toggle setting in the folder settings (FolderSettingsFragment.java)? Weā€™ll have to access this list after parsing each set of retrieved events to determine whether or not to issue a notification.

Not sure what you mean about onApiChange(), I canā€™t see any differences in that method.

The thing about different repos is probably true, I donā€™t have many repos personally. In that case, thereā€™s really no point to the global preference, so Iā€™d just add the preference to FolderSettingsFragment. You can then save the setting to an Android preference like ā€œnotifiy_on_change-reponameā€. And then enable polling if this is true for at least one repo.

Making progress, but still working on the basics. I corrected the problem with the global setting, so it works now. When events are retrieved, a notification is issued that the user can see in the notification area, and currently clicking the notification simply opens MainActivity. The problem is that once the user dismisses the notification, it does not reappear when the next retrieval occurs.

Now Iā€™m ready to actually parse the event list and search for the repo update of interest. It looks like the DownloadProgress event is the way to go. It has the information about which files in which folders are being downloaded, so this can be stored in a cache until the downloads complete, at which time a specific notification can be generated if the downloaded file is in the user-specified repo.

The last part of this notification functionality I want to complete is what happens after the user is notified. I would like to have the notification open Syncthing when tapped, and prompt the user to open the file with whatever installed app is available to do so.

For reappearing, there are some settings on Notification.Builder (though I donā€™t see anything relevant right now). Also, youā€™re supposed to use a hardcoded notification id, not a random value :wink:

You could also directly open the file/folder with an intent (like here). But youā€™d still need a list if there are multiple files. Imo a dialog would be best UX-wise.