diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bf5db0ac..f21cf0c5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -147,8 +147,8 @@
-
-
+
+
= Build.VERSION_CODES.O) {
- startForegroundService(serviceIntent);
- } else {
- startService(serviceIntent);
+ Boolean prefBroadcastServiceControl = mPreferences.getBoolean(PREF_BROADCAST_SERVICE_CONTROL, false);
+ if (!prefBroadcastServiceControl) {
+ /**
+ * SyncthingService needs to be started from this activity as the user
+ * can directly launch this activity from the recent activity switcher.
+ * Applies if PREF_BROADCAST_SERVICE_CONTROL is DISABLED (default).
+ */
+ Intent serviceIntent = new Intent(this, SyncthingService.class);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(serviceIntent);
+ } else {
+ startService(serviceIntent);
+ }
}
onNewIntent(getIntent());
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 f3a370f3..27470676 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/SettingsActivity.java
@@ -60,7 +60,7 @@ public class SettingsActivity extends SyncthingActivity {
private SettingsFragment mSettingsFragment;
public static final String EXTRA_OPEN_SUB_PREF_SCREEN =
- "com.nutomic.syncthingandroid.activities.SettingsActivity.OPEN_SUB_PREF_SCREEN";
+ "com.github.catfriend1.syncthingandroid.activities.SettingsActivity.OPEN_SUB_PREF_SCREEN";
@Override
protected void onCreate(Bundle savedInstanceState) {
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 b4974fae..a3e35a1e 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/activities/SyncConditionsActivity.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/activities/SyncConditionsActivity.java
@@ -43,10 +43,10 @@ public class SyncConditionsActivity extends SyncthingActivity {
private static final String TAG = "SyncConditionsActivity";
private static final String EXTRA_OBJECT_PREFIX_AND_ID =
- "com.nutomic.syncthingandroid.activities.SyncConditionsActivity.OBJECT_PREFIX_AND_ID";
+ "com.github.catfriend1.syncthingandroid.activities.SyncConditionsActivity.OBJECT_PREFIX_AND_ID";
private static final String EXTRA_OBJECT_READABLE_NAME =
- "com.nutomic.syncthingandroid.activities.SyncConditionsActivity.OBJECT_READABLE_NAME";
+ "com.github.catfriend1.syncthingandroid.activities.SyncConditionsActivity.OBJECT_READABLE_NAME";
// UI elements
private SwitchCompat mSyncOnWifi;
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java b/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java
index 3e2265e5..84f0d68c 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/receiver/AppConfigReceiver.java
@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
+import android.util.Log;
import com.nutomic.syncthingandroid.SyncthingApp;
import com.nutomic.syncthingandroid.service.NotificationHandler;
@@ -18,29 +19,43 @@ import javax.inject.Inject;
*/
public class AppConfigReceiver extends BroadcastReceiver {
+ private static final String TAG = "AppConfigReceiver";
+
/**
* Start the Syncthing-Service
*/
- private static final String ACTION_START = "com.nutomic.syncthingandroid.action.START";
+ private static final String ACTION_START = "com.github.catfriend1.syncthingandroid.action.START";
/**
* Stop the Syncthing-Service
* If startServiceOnBoot is enabled the service must not be stopped. Instead a
* notification is presented to the user.
*/
- private static final String ACTION_STOP = "com.nutomic.syncthingandroid.action.STOP";
+ private static final String ACTION_STOP = "com.github.catfriend1.syncthingandroid.action.STOP";
@Inject NotificationHandler mNotificationHandler;
@Override
public void onReceive(Context context, Intent intent) {
((SyncthingApp) context.getApplicationContext()).component().inject(this);
- switch (intent.getAction()) {
+ String intentAction = intent.getAction();
+ if (!getPrefBroadcastServiceControl(context)) {
+ switch (intentAction) {
+ case ACTION_START:
+ case ACTION_STOP:
+ Log.w(TAG, "Ignored intent action \"" + intentAction +
+ "\". Enable Settings > Experimental > Service Control by Broadcast if you like to control syncthing remotely.");
+ break;
+ }
+ return;
+ }
+
+ switch (intentAction) {
case ACTION_START:
BootReceiver.startServiceCompat(context);
break;
case ACTION_STOP:
- if (startServiceOnBoot(context)) {
+ if (getPrefStartServiceOnBoot(context)) {
mNotificationHandler.showStopSyncthingWarningNotification();
} else {
context.stopService(new Intent(context, SyncthingService.class));
@@ -49,7 +64,12 @@ public class AppConfigReceiver extends BroadcastReceiver {
}
}
- private static boolean startServiceOnBoot(Context context) {
+ private static boolean getPrefBroadcastServiceControl(Context context) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ return sp.getBoolean(Constants.PREF_BROADCAST_SERVICE_CONTROL, false);
+ }
+
+ private static boolean getPrefStartServiceOnBoot(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
return sp.getBoolean(Constants.PREF_START_SERVICE_ON_BOOT, false);
}
diff --git a/app/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java b/app/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java
index 1b0d7e50..897395c6 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/receiver/BootReceiver.java
@@ -29,7 +29,7 @@ public class BootReceiver extends BroadcastReceiver {
*
* https://stackoverflow.com/a/44505719/1837158
*/
- static void startServiceCompat(Context context) {
+ public static void startServiceCompat(Context context) {
Intent intent = new Intent(context, SyncthingService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
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 16461764..39260c8c 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java
@@ -35,6 +35,7 @@ public class Constants {
public static final String PREF_USE_TOR = "use_tor";
public static final String PREF_SOCKS_PROXY_ADDRESS = "socks_proxy_address";
public static final String PREF_HTTP_PROXY_ADDRESS = "http_proxy_address";
+ public static final String PREF_BROADCAST_SERVICE_CONTROL = "broadcast_service_control";
// Preferences - per Folder and Device Sync Conditions
public static final String PREF_OBJECT_PREFIX_FOLDER = "sc_folder_";
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 fee4c21a..bb98b857 100644
--- a/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java
+++ b/app/src/main/java/com/nutomic/syncthingandroid/service/SyncthingService.java
@@ -3,6 +3,7 @@ package com.nutomic.syncthingandroid.service;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.content.SharedPreferences;
import android.Manifest;
import android.os.AsyncTask;
@@ -56,70 +57,70 @@ public class SyncthingService extends Service {
* Intent action to perform a Syncthing restart.
*/
public static final String ACTION_RESTART =
- "com.nutomic.syncthingandroid.service.SyncthingService.RESTART";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.RESTART";
/**
* Intent action to perform a Syncthing stop.
*/
public static final String ACTION_STOP =
- "com.nutomic.syncthingandroid.service.SyncthingService.STOP";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.STOP";
/**
* Intent action to reset Syncthing's database.
*/
public static final String ACTION_RESET_DATABASE =
- "com.nutomic.syncthingandroid.service.SyncthingService.RESET_DATABASE";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.RESET_DATABASE";
/**
* Intent action to reset Syncthing's delta indexes.
*/
public static final String ACTION_RESET_DELTAS =
- "com.nutomic.syncthingandroid.service.SyncthingService.RESET_DELTAS";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.RESET_DELTAS";
public static final String ACTION_REFRESH_NETWORK_INFO =
- "com.nutomic.syncthingandroid.service.SyncthingService.REFRESH_NETWORK_INFO";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.REFRESH_NETWORK_INFO";
/**
* Intent action to permanently ignore a device connection request.
*/
public static final String ACTION_IGNORE_DEVICE =
- "com.nutomic.syncthingandroid.service.SyncthingService.IGNORE_DEVICE";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.IGNORE_DEVICE";
/**
* Intent action to permanently ignore a folder share request.
*/
public static final String ACTION_IGNORE_FOLDER =
- "com.nutomic.syncthingandroid.service.SyncthingService.IGNORE_FOLDER";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.IGNORE_FOLDER";
/**
* Intent action to override folder changes.
*/
public static final String ACTION_OVERRIDE_CHANGES =
- "com.nutomic.syncthingandroid.service.SyncthingService.OVERRIDE_CHANGES";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.OVERRIDE_CHANGES";
/**
* Extra used together with ACTION_IGNORE_DEVICE, ACTION_IGNORE_FOLDER.
*/
public static final String EXTRA_NOTIFICATION_ID =
- "com.nutomic.syncthingandroid.service.SyncthingService.EXTRA_NOTIFICATION_ID";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.EXTRA_NOTIFICATION_ID";
/**
* Extra used together with ACTION_IGNORE_DEVICE
*/
public static final String EXTRA_DEVICE_ID =
- "com.nutomic.syncthingandroid.service.SyncthingService.EXTRA_DEVICE_ID";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.EXTRA_DEVICE_ID";
/**
* Extra used together with ACTION_IGNORE_FOLDER
*/
public static final String EXTRA_FOLDER_ID =
- "com.nutomic.syncthingandroid.service.SyncthingService.EXTRA_FOLDER_ID";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.EXTRA_FOLDER_ID";
/**
* Extra used together with ACTION_STOP.
*/
public static final String EXTRA_STOP_AFTER_CRASHED_NATIVE =
- "com.nutomic.syncthingandroid.service.SyncthingService.EXTRA_STOP_AFTER_CRASHED_NATIVE";
+ "com.github.catfriend1.syncthingandroid.SyncthingService.EXTRA_STOP_AFTER_CRASHED_NATIVE";
public interface OnServiceStateChangeListener {
void onServiceStateChange(State currentState);
@@ -208,6 +209,14 @@ public class SyncthingService extends Service {
*/
private boolean mStoragePermissionGranted = false;
+ /**
+ * True if experimental option PREF_BROADCAST_SERVICE_CONTROL is set.
+ * Disables run condition monitor completely because the user chose to
+ * control the service by sending broadcasts, e.g. from third-party
+ * automation apps.
+ */
+ private boolean mPrefBroadcastServiceControl = false;
+
/**
* Starts the native binary.
*/
@@ -231,6 +240,9 @@ public class SyncthingService extends Service {
if (mNotificationHandler != null) {
mNotificationHandler.setAppShutdownInProgress(false);
}
+
+ // Read pref.
+ mPrefBroadcastServiceControl = mPreferences.getBoolean(Constants.PREF_BROADCAST_SERVICE_CONTROL, false);
}
/**
@@ -260,17 +272,28 @@ public class SyncthingService extends Service {
onServiceStateChange(mCurrentState);
}
}
- if (mRunConditionMonitor == null) {
+
+ if (mPrefBroadcastServiceControl) {
+ Log.i(TAG, "onStartCommand: mPrefBroadcastServiceControl == true, RunConditionMonitor is disabled.");
/**
- * Instantiate the run condition monitor on first onStartCommand and
- * enable callback on run condition change affecting the final decision to
- * run/terminate syncthing. After initial run conditions are collected
- * the first decision is sent to {@link onShouldRunDecisionChanged}.
+ * Directly use the callback which normally is invoked by RunConditionMonitor to start the
+ * syncthing native unconditionally.
*/
- mRunConditionMonitor = new RunConditionMonitor(SyncthingService.this,
- this::onShouldRunDecisionChanged,
- this::onSyncPreconditionChanged
- );
+ onShouldRunDecisionChanged(true);
+ } else {
+ // Run condition monitor is enabled.
+ if (mRunConditionMonitor == null) {
+ /**
+ * Instantiate the run condition monitor on first onStartCommand and
+ * enable callback on run condition change affecting the final decision to
+ * run/terminate syncthing. After initial run conditions are collected
+ * the first decision is sent to {@link onShouldRunDecisionChanged}.
+ */
+ mRunConditionMonitor = new RunConditionMonitor(SyncthingService.this,
+ this::onShouldRunDecisionChanged,
+ this::onSyncPreconditionChanged
+ );
+ }
}
mNotificationHandler.updatePersistentNotification(this);
@@ -334,7 +357,9 @@ public class SyncthingService extends Service {
shutdown(State.DISABLED);
}
} else if (ACTION_REFRESH_NETWORK_INFO.equals(intent.getAction())) {
- mRunConditionMonitor.updateShouldRunDecision();
+ if (mRunConditionMonitor != null) {
+ mRunConditionMonitor.updateShouldRunDecision();
+ }
} else if (ACTION_IGNORE_DEVICE.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
// mRestApi is not null due to State.ACTIVE
mRestApi.ignoreDevice(intent.getStringExtra(EXTRA_DEVICE_ID));
@@ -739,10 +764,17 @@ public class SyncthingService extends Service {
}
public String getRunDecisionExplanation() {
- if (mRunConditionMonitor == null) {
- return "This should not happen: mRunConditionMonitor is not instantiated.";
+ if (mRunConditionMonitor != null) {
+ return mRunConditionMonitor.getRunDecisionExplanation();
}
- return mRunConditionMonitor.getRunDecisionExplanation();
+
+ Resources res = getResources();
+ if (mPrefBroadcastServiceControl) {
+ return res.getString(R.string.reason_broadcast_controlled);
+ }
+
+ // mRunConditionMonitor == null
+ return res.getString(R.string.reason_run_condition_monitor_not_instantiated);
}
/**
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index ca4385ef..fae21020 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -57,7 +57,7 @@ Bitte melden Sie auftretende Probleme via GitHub.
Zu Deiner Erinnerung: Du hast Syncthing eingerichtet, automatisch beim Hochfahren zu starten. Deshalb überwacht es die Laufkonditionen und synchronisiert, wenn die Bedingungen zutreffen. Du solltest nur manuell beenden, wenn Du größere Probleme feststellst. Andernfalls schalte \"Automatisch beim Hochfahren starten\" in den Einstellungen aus. Möchtest Du jetzt beenden, bis das Gerät neu gestartet wurde?
- Verzeichnis hinzufügen
+ Ordner hinzufügen
Geräte-ID teilen
@@ -95,7 +95,7 @@ Bitte melden Sie auftretende Probleme via GitHub.
- Verzeichnisse
+ Ordner
Keine Verzeichnisse gefunden
@@ -207,13 +207,13 @@ Bitte melden Sie auftretende Probleme via GitHub.
Versionen behalten
- Verzeichnis löschen
+ Ordner löschen
- Verzeichnis erstellen
+ Ordner erstellen
- Verzeichnis bearbeiten
+ Ordner bearbeiten
Erstellen
@@ -493,6 +493,10 @@ Bitte melden Sie auftretende Probleme via GitHub.
Für Abwärtskompatibilität soll Syncthing die alten Hashfunktionen verwenden
+ Dienstkontrolle über Broadcast
+
+ Standard: Deaktiviert. Aktiviere diese Option, um den Dienst durch Broadcasts z. B. mit Drittanbieter Automatisierungsapps zu starten und zu stoppen. Hinweis: Nach dem Ändern dieser Option musst du die App manuell neu starten.
+
Neustart nach Aufwachen
Standard: Aktiviert. Das Deaktivieren dieser Funktion kann verzögertes Ordner-Scannen und Wiederverbinden von Geräten zur Folge haben. Dafür spart es Akku.
@@ -561,7 +565,7 @@ Bitte melden Sie auftretende Probleme via GitHub.
Syncthing API Key (Klicke zum Kopieren)
-
+
Syncthing API Key in die Zwischenablage kopiert
@@ -666,6 +670,8 @@ Bitte melden Sie auftretende Probleme via GitHub.
Syncthing läuft nicht, weil Du verboten hast, dass es bei getakteten WLAN-Verbindungen läuft.
Du hast \'Starte in ausgewählten WLAN-Netzwerken\' in den Einstellungen aktiviert. Die Android-tandorterfassung ist derzeit ausgeschaltet. Aufgrund von Android-Beschränkungen kann Syncthing den aktuellen WLAN-Netzwerknamen nicht ermitteln, um zu entscheiden, ob es starten soll. Lösung: Schalte den Standort ein und verbinde WLAN erneut.
Syncthing läuft, weil Du erlaubt hast, dass es bei eingeschaltetem Flugzeugmodus läuft.
+ Syncthing hört auf Broadcasts, die von einer Drittanbieter-App oder über ADB gesendet werden. Du kannst zu den eingebauten Laufkonditionen zurück wechseln, indem Du unter \'Einstellungen\' > \'Experimentell\' > \'Dienstkontrolle über Broadcast\' deaktivierst.
+ Laufkonditionen-Überwachung ist nicht instantiiert. Bitte starte die App neu und erstelle einen Fehlerbericht, wenn das Problem nach dem Neustart nicht verschwindet.
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index bbad55b2..580b4c9d 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -597,7 +597,6 @@ Vänligen rapportera eventuella problem du stöter på via Github.
Syncthing får köras på det aktuella Wi-Fi-nätverket.
Syncthing körs inte eftersom det aktuella Wi-Fi-nätverkets namn inte är vitlistat.
Syncthing körs som du tillät att den ska köras när flygläget är aktivt.
-
Ingen Wi-Fi-SSID är vitlistad. Ange några i inställningarna.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d85df797..8392a5a7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -493,6 +493,10 @@ Please report any problems you encounter via Github.
Force Syncthing to use legacy hashing package for compatibility purposes
+ Service Control by Broadcast
+
+ Default: Disabled. Enable this option to start and stop the service by sending broadcasts, e.g. from third-party automation apps. Note: You have to restart the app manually after changing this option.
+
Restart on Wakeup
Default: Enabled. Disabling this feature may result in folder scans and device reconnects being delayed to save battery.
@@ -569,7 +573,7 @@ Please report any problems you encounter via Github.
Syncthing API Key (click to copy)
-
+
Syncthing API key copied to clipboard
@@ -674,6 +678,8 @@ Please report any problems you encounter via Github.
Syncthing is not running as you disallowed it to run on metered WiFi connections.
You enabled \'Run on selected WiFi networks\' in the settings. Android location services are currently turned off. According to Android restrictions, Syncthing cannot determine the current WiFi network name to decide if it should run. Solution: Turn location on and reconnect WiFi.
Syncthing is running as you allowed it to run when flight mode is active.
+ Syncthing is listening to broadcasts sent by a third-party app or ADB. You can switch back to use the built-in run conditions by disabling \'Settings\' > \'Experimental\' > \'Service Control by Broadcast\'.
+ RunConditionMonitor is not instantiated. Please restart the app and file a bug report if this error doesn\'t disappear after the restart.
diff --git a/app/src/main/res/xml/app_settings.xml b/app/src/main/res/xml/app_settings.xml
index 3e272d62..1dd18292 100644
--- a/app/src/main/res/xml/app_settings.xml
+++ b/app/src/main/res/xml/app_settings.xml
@@ -255,6 +255,11 @@
android:title="@string/use_legacy_hashing_title"
android:summary="@string/use_legacy_hashing_summary" />
+
+