mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-22 20:31:16 +00:00
Show reasons for disabled service in notification dialog (#1264)
This commit is contained in:
parent
9796d7beb1
commit
700c55e9d3
5 changed files with 233 additions and 37 deletions
|
@ -5,18 +5,23 @@ import android.content.Intent;
|
|||
import android.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.view.View;
|
||||
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.databinding.DialogLoadingBinding;
|
||||
import com.nutomic.syncthingandroid.model.RunConditionCheckResult;
|
||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||
import com.nutomic.syncthingandroid.service.SyncthingService.State;
|
||||
import com.nutomic.syncthingandroid.util.Util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.nutomic.syncthingandroid.model.RunConditionCheckResult.*;
|
||||
|
||||
/**
|
||||
* Handles loading/disabled dialogs.
|
||||
*/
|
||||
|
@ -32,8 +37,10 @@ public abstract class StateDialogActivity extends SyncthingActivity {
|
|||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
registerOnServiceConnectedListener(() ->
|
||||
getService().registerOnServiceStateChangeListener(this::onServiceStateChange));
|
||||
registerOnServiceConnectedListener(() -> {
|
||||
getService().registerOnServiceStateChangeListener(this::onServiceStateChange);
|
||||
getService().registerOnRunConditionCheckResultChange(this::onRunConditionCheckResultChange);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,6 +69,7 @@ public abstract class StateDialogActivity extends SyncthingActivity {
|
|||
super.onDestroy();
|
||||
if (getService() != null) {
|
||||
getService().unregisterOnServiceStateChangeListener(this::onServiceStateChange);
|
||||
getService().unregisterOnRunConditionCheckResultChange(this::onRunConditionCheckResultChange);
|
||||
}
|
||||
dismissDisabledDialog();
|
||||
}
|
||||
|
@ -89,13 +97,20 @@ public abstract class StateDialogActivity extends SyncthingActivity {
|
|||
}
|
||||
}
|
||||
|
||||
private void onRunConditionCheckResultChange(RunConditionCheckResult result) {
|
||||
if (mDisabledDialog != null && mDisabledDialog.isShowing()) {
|
||||
mDisabledDialog.setMessage(getDisabledDialogMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void showDisabledDialog() {
|
||||
if (this.isFinishing() && (mDisabledDialog != null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDisabledDialog = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.syncthing_disabled_title)
|
||||
.setMessage(R.string.syncthing_disabled_message)
|
||||
.setMessage(getDisabledDialogMessage())
|
||||
.setPositiveButton(R.string.syncthing_disabled_change_settings,
|
||||
(dialogInterface, i) -> {
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
|
@ -110,6 +125,26 @@ public abstract class StateDialogActivity extends SyncthingActivity {
|
|||
.show();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private StringBuilder getDisabledDialogMessage() {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append(this.getResources().getString(R.string.syncthing_disabled_message));
|
||||
Collection<BlockerReason> reasons = getService().getCurrentRunConditionCheckResult().getBlockReasons();
|
||||
if (!reasons.isEmpty()) {
|
||||
message.append("\n");
|
||||
message.append("\n");
|
||||
message.append(this.getResources().getString(R.string.syncthing_disabled_reason_heading));
|
||||
int count = 0;
|
||||
for (BlockerReason reason : reasons) {
|
||||
count++;
|
||||
message.append("\n");
|
||||
if (reasons.size() > 1) message.append(count + ". ");
|
||||
message.append(this.getString(reason.getResId()));
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private void dismissDisabledDialog() {
|
||||
Util.dismissDialogSafe(mDisabledDialog, this);
|
||||
mDisabledDialog = null;
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package com.nutomic.syncthingandroid.model;
|
||||
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class RunConditionCheckResult {
|
||||
|
||||
public enum BlockerReason {
|
||||
ON_BATTERY(R.string.syncthing_disabled_reason_on_battery),
|
||||
ON_CHARGER(R.string.syncthing_disabled_reason_on_charger),
|
||||
POWERSAVING_ENABLED(R.string.syncthing_disabled_reason_powersaving),
|
||||
GLOBAL_SYNC_DISABLED(R.string.syncthing_disabled_reason_android_sync_disabled),
|
||||
WIFI_SSID_NOT_WHITELISTED(R.string.syncthing_disabled_reason_wifi_ssid_not_whitelisted),
|
||||
WIFI_WIFI_IS_METERED(R.string.syncthing_disabled_reason_wifi_is_metered),
|
||||
NO_NETWORK_OR_FLIGHTMODE(R.string.syncthing_disabled_reason_no_network_or_flightmode),
|
||||
NO_MOBILE_CONNECTION(R.string.syncthing_disabled_reason_no_mobile_connection),
|
||||
NO_WIFI_CONNECTION(R.string.syncthing_disabled_reason_no_wifi_connection),
|
||||
NO_ALLOWED_NETWORK(R.string.syncthing_disabled_reason_no_allowed_method);
|
||||
|
||||
private final int resId;
|
||||
|
||||
BlockerReason(int resId) {
|
||||
this.resId = resId;
|
||||
}
|
||||
|
||||
public int getResId() {
|
||||
return resId;
|
||||
}
|
||||
}
|
||||
|
||||
public static final RunConditionCheckResult SHOULD_RUN = new RunConditionCheckResult();
|
||||
|
||||
private final boolean mShouldRun;
|
||||
private final List<BlockerReason> mBlockReasons;
|
||||
|
||||
/**
|
||||
* Use SHOULD_RUN instead.
|
||||
* Note: of course anybody could still construct it by providing an empty list to the other
|
||||
* constructor.
|
||||
*/
|
||||
private RunConditionCheckResult() {
|
||||
this(Collections.emptyList());
|
||||
}
|
||||
|
||||
public RunConditionCheckResult(List<BlockerReason> blockReasons) {
|
||||
mBlockReasons = Collections.unmodifiableList(blockReasons);
|
||||
mShouldRun = blockReasons.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
public List<BlockerReason> getBlockReasons() {
|
||||
return mBlockReasons;
|
||||
}
|
||||
|
||||
public boolean isShouldRun() {
|
||||
return mShouldRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
RunConditionCheckResult that = (RunConditionCheckResult) o;
|
||||
|
||||
if (mShouldRun != that.mShouldRun) return false;
|
||||
return mBlockReasons.equals(that.mBlockReasons);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (mShouldRun ? 1 : 0);
|
||||
result = 31 * result + mBlockReasons.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -16,19 +16,21 @@ import android.os.BatteryManager;
|
|||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.nutomic.syncthingandroid.SyncthingApp;
|
||||
import com.nutomic.syncthingandroid.service.ReceiverManager;
|
||||
import com.nutomic.syncthingandroid.model.RunConditionCheckResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static com.nutomic.syncthingandroid.model.RunConditionCheckResult.*;
|
||||
import static com.nutomic.syncthingandroid.model.RunConditionCheckResult.BlockerReason.*;
|
||||
|
||||
/**
|
||||
* Holds information about the current wifi and charging state of the device.
|
||||
*
|
||||
|
@ -52,7 +54,7 @@ public class RunConditionMonitor {
|
|||
};
|
||||
|
||||
public interface OnRunConditionChangedListener {
|
||||
void onRunConditionChanged(boolean shouldRun);
|
||||
void onRunConditionChanged(RunConditionCheckResult result);
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
|
@ -60,14 +62,14 @@ public class RunConditionMonitor {
|
|||
private ReceiverManager mReceiverManager;
|
||||
|
||||
/**
|
||||
* Sending callback notifications through {@link OnDeviceStateChangedListener} is enabled if not null.
|
||||
* Sending callback notifications through {@link OnRunConditionChangedListener} is enabled if not null.
|
||||
*/
|
||||
private @Nullable OnRunConditionChangedListener mOnRunConditionChangedListener = null;
|
||||
|
||||
/**
|
||||
* Stores the result of the last call to {@link decideShouldRun}.
|
||||
* Stores the result of the last call to {@link #decideShouldRun()}.
|
||||
*/
|
||||
private boolean lastDeterminedShouldRun = false;
|
||||
private RunConditionCheckResult lastRunConditionCheckResult;
|
||||
|
||||
public RunConditionMonitor(Context context, OnRunConditionChangedListener listener) {
|
||||
Log.v(TAG, "Created new instance");
|
||||
|
@ -140,21 +142,25 @@ public class RunConditionMonitor {
|
|||
}
|
||||
|
||||
public void updateShouldRunDecision() {
|
||||
// Check if the current conditions changed the result of decideShouldRun()
|
||||
// Reason if the current conditions changed the result of decideShouldRun()
|
||||
// compared to the last determined result.
|
||||
boolean newShouldRun = decideShouldRun();
|
||||
if (newShouldRun != lastDeterminedShouldRun) {
|
||||
if (mOnRunConditionChangedListener != null) {
|
||||
mOnRunConditionChangedListener.onRunConditionChanged(newShouldRun);
|
||||
RunConditionCheckResult result = decideShouldRun();
|
||||
boolean change;
|
||||
synchronized (this) {
|
||||
change = lastRunConditionCheckResult == null || !lastRunConditionCheckResult.equals(result);
|
||||
lastRunConditionCheckResult = result;
|
||||
}
|
||||
if (change) {
|
||||
if (mOnRunConditionChangedListener != null) {
|
||||
mOnRunConditionChangedListener.onRunConditionChanged(result);
|
||||
}
|
||||
lastDeterminedShouldRun = newShouldRun;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if Syncthing should currently run.
|
||||
*/
|
||||
private boolean decideShouldRun() {
|
||||
private RunConditionCheckResult decideShouldRun() {
|
||||
// Get run conditions preferences.
|
||||
boolean prefRunOnMobileData= mPreferences.getBoolean(Constants.PREF_RUN_ON_MOBILE_DATA, false);
|
||||
boolean prefRunOnWifi= mPreferences.getBoolean(Constants.PREF_RUN_ON_WIFI, true);
|
||||
|
@ -166,18 +172,20 @@ public class RunConditionMonitor {
|
|||
boolean prefRespectPowerSaving = mPreferences.getBoolean(Constants.PREF_RESPECT_BATTERY_SAVING, true);
|
||||
boolean prefRespectMasterSync = mPreferences.getBoolean(Constants.PREF_RESPECT_MASTER_SYNC, false);
|
||||
|
||||
List<BlockerReason> blockerReasons = new ArrayList<>();
|
||||
|
||||
// PREF_POWER_SOURCE
|
||||
switch (prefPowerSource) {
|
||||
case POWER_SOURCE_CHARGER:
|
||||
if (!isCharging()) {
|
||||
Log.v(TAG, "decideShouldRun: POWER_SOURCE_AC && !isCharging");
|
||||
return false;
|
||||
blockerReasons.add(ON_BATTERY);
|
||||
}
|
||||
break;
|
||||
case POWER_SOURCE_BATTERY:
|
||||
if (isCharging()) {
|
||||
Log.v(TAG, "decideShouldRun: POWER_SOURCE_BATTERY && isCharging");
|
||||
return false;
|
||||
blockerReasons.add(ON_CHARGER);
|
||||
}
|
||||
break;
|
||||
case POWER_SOURCE_CHARGER_BATTERY:
|
||||
|
@ -189,35 +197,43 @@ public class RunConditionMonitor {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (prefRespectPowerSaving && isPowerSaving()) {
|
||||
Log.v(TAG, "decideShouldRun: prefRespectPowerSaving && isPowerSaving");
|
||||
return false;
|
||||
blockerReasons.add(POWERSAVING_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
// Android global AutoSync setting.
|
||||
if (prefRespectMasterSync && !ContentResolver.getMasterSyncAutomatically()) {
|
||||
Log.v(TAG, "decideShouldRun: prefRespectMasterSync && !getMasterSyncAutomatically");
|
||||
return false;
|
||||
blockerReasons.add(GLOBAL_SYNC_DISABLED);
|
||||
}
|
||||
|
||||
// Run on mobile data.
|
||||
if (prefRunOnMobileData && isMobileDataConnection()) {
|
||||
if (blockerReasons.isEmpty() && prefRunOnMobileData && isMobileDataConnection()) {
|
||||
Log.v(TAG, "decideShouldRun: prefRunOnMobileData && isMobileDataConnection");
|
||||
return true;
|
||||
return SHOULD_RUN;
|
||||
}
|
||||
|
||||
// Run on wifi.
|
||||
if (prefRunOnWifi && isWifiOrEthernetConnection()) {
|
||||
if (prefRunOnMeteredWifi) {
|
||||
// We are on non-metered or metered wifi. Check if wifi whitelist run condition is met.
|
||||
// We are on non-metered or metered wifi. Reason if wifi whitelist run condition is met.
|
||||
if (wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
|
||||
Log.v(TAG, "decideShouldRun: prefRunOnWifi && isWifiOrEthernetConnection && prefRunOnMeteredWifi && wifiWhitelistConditionMet");
|
||||
return true;
|
||||
if (blockerReasons.isEmpty()) return SHOULD_RUN;
|
||||
} else {
|
||||
blockerReasons.add(WIFI_SSID_NOT_WHITELISTED);
|
||||
}
|
||||
} else {
|
||||
// Check if we are on a non-metered wifi and if wifi whitelist run condition is met.
|
||||
if (!isMeteredNetworkConnection() && wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
|
||||
// Reason if we are on a non-metered wifi and if wifi whitelist run condition is met.
|
||||
if (!isMeteredNetworkConnection()) {
|
||||
if (wifiWhitelistConditionMet(prefWifiWhitelistEnabled, whitelistedWifiSsids)) {
|
||||
Log.v(TAG, "decideShouldRun: prefRunOnWifi && isWifiOrEthernetConnection && !prefRunOnMeteredWifi && !isMeteredNetworkConnection && wifiWhitelistConditionMet");
|
||||
return true;
|
||||
if (blockerReasons.isEmpty()) return SHOULD_RUN;
|
||||
} else {
|
||||
blockerReasons.add(WIFI_SSID_NOT_WHITELISTED);
|
||||
}
|
||||
} else {
|
||||
blockerReasons.add(WIFI_WIFI_IS_METERED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,14 +241,27 @@ public class RunConditionMonitor {
|
|||
// Run in flight mode.
|
||||
if (prefRunInFlightMode && isFlightMode()) {
|
||||
Log.v(TAG, "decideShouldRun: prefRunInFlightMode && isFlightMode");
|
||||
return true;
|
||||
if (blockerReasons.isEmpty()) return SHOULD_RUN;
|
||||
}
|
||||
|
||||
/**
|
||||
* If none of the above run conditions matched, don't run.
|
||||
*/
|
||||
Log.v(TAG, "decideShouldRun: return false");
|
||||
return false;
|
||||
if (blockerReasons.isEmpty()) {
|
||||
if (isFlightMode()) {
|
||||
blockerReasons.add(NO_NETWORK_OR_FLIGHTMODE);
|
||||
} else if (!prefRunOnWifi && !prefRunOnMobileData) {
|
||||
blockerReasons.add(NO_ALLOWED_NETWORK);
|
||||
} else if (prefRunOnMobileData) {
|
||||
blockerReasons.add(NO_MOBILE_CONNECTION);
|
||||
} else if (prefRunOnWifi) {
|
||||
blockerReasons.add(NO_WIFI_CONNECTION);
|
||||
} else {
|
||||
blockerReasons.add(NO_NETWORK_OR_FLIGHTMODE);
|
||||
}
|
||||
}
|
||||
return new RunConditionCheckResult(blockerReasons);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,33 +1,34 @@
|
|||
package com.nutomic.syncthingandroid.service;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.SharedPreferences;
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.PRNGFixes;
|
||||
import com.annimon.stream.Stream;
|
||||
import com.google.common.io.Files;
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.SyncthingApp;
|
||||
import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask;
|
||||
import com.nutomic.syncthingandroid.model.Folder;
|
||||
import com.nutomic.syncthingandroid.model.RunConditionCheckResult;
|
||||
import com.nutomic.syncthingandroid.util.ConfigXml;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
@ -99,6 +100,10 @@ public class SyncthingService extends Service {
|
|||
void onServiceStateChange(State currentState);
|
||||
}
|
||||
|
||||
public interface OnRunConditionCheckResultListener {
|
||||
void onRunConditionCheckResultChanged(RunConditionCheckResult result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the current state of SyncthingService and of Syncthing itself.
|
||||
*/
|
||||
|
@ -124,6 +129,7 @@ public class SyncthingService extends Service {
|
|||
* {@link onStartCommand}.
|
||||
*/
|
||||
private State mCurrentState = State.DISABLED;
|
||||
private AtomicReference<RunConditionCheckResult> mCurrentCheckResult = new AtomicReference<>(RunConditionCheckResult.SHOULD_RUN);
|
||||
|
||||
private ConfigXml mConfig;
|
||||
private @Nullable PollWebGuiAvailableTask mPollWebGuiAvailableTask = null;
|
||||
|
@ -136,6 +142,7 @@ public class SyncthingService extends Service {
|
|||
private Handler mHandler;
|
||||
|
||||
private final HashSet<OnServiceStateChangeListener> mOnServiceStateChangeListeners = new HashSet<>();
|
||||
private final HashSet<OnRunConditionCheckResultListener> mOnRunConditionCheckResultListeners = new HashSet<>();
|
||||
private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this);
|
||||
|
||||
@Inject NotificationHandler mNotificationHandler;
|
||||
|
@ -262,7 +269,13 @@ public class SyncthingService extends Service {
|
|||
* function is called to notify this class to run/terminate the syncthing binary.
|
||||
* {@link #onServiceStateChange} is called while applying the decision change.
|
||||
*/
|
||||
private void onUpdatedShouldRunDecision(boolean newShouldRunDecision) {
|
||||
private void onUpdatedShouldRunDecision(RunConditionCheckResult result) {
|
||||
boolean newShouldRunDecision = result.isShouldRun();
|
||||
boolean reasonsChanged = !mCurrentCheckResult.getAndSet(result).equals(result);
|
||||
if (reasonsChanged) {
|
||||
onRunConditionCheckResultChange(result);
|
||||
}
|
||||
|
||||
if (newShouldRunDecision != mLastDeterminedShouldRun) {
|
||||
Log.i(TAG, "shouldRun decision changed to " + newShouldRunDecision + " according to configured run conditions.");
|
||||
mLastDeterminedShouldRun = newShouldRunDecision;
|
||||
|
@ -578,6 +591,30 @@ public class SyncthingService extends Service {
|
|||
});
|
||||
}
|
||||
|
||||
public void registerOnRunConditionCheckResultChange(OnRunConditionCheckResultListener listener) {
|
||||
listener.onRunConditionCheckResultChanged(mCurrentCheckResult.get());
|
||||
mOnRunConditionCheckResultListeners.add(listener);
|
||||
}
|
||||
|
||||
public void unregisterOnRunConditionCheckResultChange(OnRunConditionCheckResultListener listener) {
|
||||
mOnRunConditionCheckResultListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void onRunConditionCheckResultChange(RunConditionCheckResult result) {
|
||||
mHandler.post(() -> {
|
||||
for (Iterator<OnRunConditionCheckResultListener> i = mOnRunConditionCheckResultListeners.iterator();
|
||||
i.hasNext(); ) {
|
||||
OnRunConditionCheckResultListener listener = i.next();
|
||||
if (listener != null) {
|
||||
listener.onRunConditionCheckResultChanged(result);
|
||||
} else {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public URL getWebGuiUrl() {
|
||||
return mConfig.getWebGuiUrl();
|
||||
}
|
||||
|
@ -586,6 +623,10 @@ public class SyncthingService extends Service {
|
|||
return mCurrentState;
|
||||
}
|
||||
|
||||
public RunConditionCheckResult getCurrentRunConditionCheckResult() {
|
||||
return mCurrentCheckResult.get();
|
||||
}
|
||||
|
||||
public NotificationHandler getNotificationHandler() {
|
||||
return mNotificationHandler;
|
||||
}
|
||||
|
|
|
@ -653,6 +653,19 @@ Please report any problems you encounter via Github.</string>
|
|||
<!-- Button text on the "syncthing disabled" dialog, used as menu item to stop syncthing service if "always_run_in_background" is true -->
|
||||
<string name="exit">Exit</string>
|
||||
|
||||
<!-- Reasons for "syncthing disabled" dialog -->
|
||||
<string name="syncthing_disabled_reason_heading">Reasons:</string>
|
||||
<string name="syncthing_disabled_reason_on_battery">Device is running on battery</string>
|
||||
<string name="syncthing_disabled_reason_on_charger">Device is running on charger</string>
|
||||
<string name="syncthing_disabled_reason_powersaving">Device is in power-saving mode</string>
|
||||
<string name="syncthing_disabled_reason_android_sync_disabled">Global Synchronization is disabled</string>
|
||||
<string name="syncthing_disabled_reason_wifi_ssid_not_whitelisted">Current WiFi SSID is not whitelisted</string>
|
||||
<string name="syncthing_disabled_reason_wifi_is_metered">Current WiFi is metered</string>
|
||||
<string name="syncthing_disabled_reason_no_network_or_flightmode">No network connection or airplane mode enabled</string>
|
||||
<string name="syncthing_disabled_reason_no_mobile_connection">Not connected to mobile data</string>
|
||||
<string name="syncthing_disabled_reason_no_wifi_connection">Not connected to WiFi</string>
|
||||
<string name="syncthing_disabled_reason_no_allowed_method">Not configured to sync on WiFi nor mobile data</string>
|
||||
|
||||
<!-- Title of the notification shown while syncthing is running and enabled -->
|
||||
<string name="syncthing_active">Syncthing is running</string>
|
||||
|
||||
|
|
Loading…
Reference in a new issue