mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-11-29 15:51:17 +00:00
Refactor DeviceStateHolder and its receivers into RunConditionMonitor (#1187)
This commit is contained in:
parent
6ead66b359
commit
02b6f987eb
11 changed files with 316 additions and 410 deletions
|
@ -5,7 +5,7 @@ import com.nutomic.syncthingandroid.activities.FolderPickerActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
import com.nutomic.syncthingandroid.activities.SettingsActivity;
|
||||||
import com.nutomic.syncthingandroid.receiver.AppConfigReceiver;
|
import com.nutomic.syncthingandroid.receiver.AppConfigReceiver;
|
||||||
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
import com.nutomic.syncthingandroid.service.RunConditionMonitor;
|
||||||
import com.nutomic.syncthingandroid.service.EventProcessor;
|
import com.nutomic.syncthingandroid.service.EventProcessor;
|
||||||
import com.nutomic.syncthingandroid.service.NotificationHandler;
|
import com.nutomic.syncthingandroid.service.NotificationHandler;
|
||||||
import com.nutomic.syncthingandroid.service.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
|
@ -27,7 +27,7 @@ public interface DaggerComponent {
|
||||||
void inject(FolderPickerActivity activity);
|
void inject(FolderPickerActivity activity);
|
||||||
void inject(Languages languages);
|
void inject(Languages languages);
|
||||||
void inject(SyncthingService service);
|
void inject(SyncthingService service);
|
||||||
void inject(DeviceStateHolder deviceStateHolder);
|
void inject(RunConditionMonitor runConditionMonitor);
|
||||||
void inject(EventProcessor eventProcessor);
|
void inject(EventProcessor eventProcessor);
|
||||||
void inject(SyncthingRunnable syncthingRunnable);
|
void inject(SyncthingRunnable syncthingRunnable);
|
||||||
void inject(NotificationHandler notificationHandler);
|
void inject(NotificationHandler notificationHandler);
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package com.nutomic.syncthingandroid.fragments;
|
package com.nutomic.syncthingandroid.fragments;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -22,7 +24,6 @@ import com.nutomic.syncthingandroid.model.Connections;
|
||||||
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;
|
||||||
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
|
||||||
import com.nutomic.syncthingandroid.service.RestApi;
|
import com.nutomic.syncthingandroid.service.RestApi;
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
import com.nutomic.syncthingandroid.util.Util;
|
import com.nutomic.syncthingandroid.util.Util;
|
||||||
|
@ -115,7 +116,7 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateExitButtonVisibility() {
|
private void updateExitButtonVisibility() {
|
||||||
boolean alwaysInBackground = DeviceStateHolder.alwaysRunInBackground(getActivity());
|
boolean alwaysInBackground = alwaysRunInBackground();
|
||||||
mExitButton.setVisibility(alwaysInBackground ? View.GONE : View.VISIBLE);
|
mExitButton.setVisibility(alwaysInBackground ? View.GONE : View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,4 +255,9 @@ public class DrawerFragment extends Fragment implements View.OnClickListener {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean alwaysRunInBackground() {
|
||||||
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||||
|
return sp.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,12 @@ package com.nutomic.syncthingandroid.receiver;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.SyncthingApp;
|
import com.nutomic.syncthingandroid.SyncthingApp;
|
||||||
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
|
||||||
import com.nutomic.syncthingandroid.service.NotificationHandler;
|
import com.nutomic.syncthingandroid.service.NotificationHandler;
|
||||||
|
import com.nutomic.syncthingandroid.service.Constants;
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -38,7 +40,7 @@ public class AppConfigReceiver extends BroadcastReceiver {
|
||||||
BootReceiver.startServiceCompat(context);
|
BootReceiver.startServiceCompat(context);
|
||||||
break;
|
break;
|
||||||
case ACTION_STOP:
|
case ACTION_STOP:
|
||||||
if (DeviceStateHolder.alwaysRunInBackground(context)) {
|
if (alwaysRunInBackground(context)) {
|
||||||
mNotificationHandler.showStopSyncthingWarningNotification();
|
mNotificationHandler.showStopSyncthingWarningNotification();
|
||||||
} else {
|
} else {
|
||||||
context.stopService(new Intent(context, SyncthingService.class));
|
context.stopService(new Intent(context, SyncthingService.class));
|
||||||
|
@ -46,4 +48,9 @@ public class AppConfigReceiver extends BroadcastReceiver {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean alwaysRunInBackground(Context context) {
|
||||||
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
return sp.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
package com.nutomic.syncthingandroid.receiver;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.BatteryManager;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives battery plug/unplug intents and sends the charging state to {@link SyncthingService}.
|
|
||||||
*/
|
|
||||||
public class BatteryReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (!Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())
|
|
||||||
&& !Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!DeviceStateHolder.alwaysRunInBackground(context))
|
|
||||||
return;
|
|
||||||
|
|
||||||
boolean isCharging = Intent.ACTION_POWER_CONNECTED.equals(intent.getAction());
|
|
||||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
|
|
||||||
Intent i = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED);
|
|
||||||
i.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
|
|
||||||
lbm.sendBroadcast(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current charging status without waiting for connected/disconnected events.
|
|
||||||
*/
|
|
||||||
public static void updateInitialChargingStatus(Context context) {
|
|
||||||
Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
|
||||||
int status = batteryIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
|
|
||||||
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
|
|
||||||
status == BatteryManager.BATTERY_STATUS_FULL;
|
|
||||||
|
|
||||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
|
|
||||||
Intent intent = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED);
|
|
||||||
intent.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
|
|
||||||
lbm.sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,9 +3,11 @@ package com.nutomic.syncthingandroid.receiver;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
import com.nutomic.syncthingandroid.service.Constants;
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
import com.nutomic.syncthingandroid.service.SyncthingService;
|
||||||
|
|
||||||
public class BootReceiver extends BroadcastReceiver {
|
public class BootReceiver extends BroadcastReceiver {
|
||||||
|
@ -16,7 +18,7 @@ public class BootReceiver extends BroadcastReceiver {
|
||||||
!intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED))
|
!intent.getAction().equals(Intent.ACTION_MY_PACKAGE_REPLACED))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!DeviceStateHolder.alwaysRunInBackground(context))
|
if (!alwaysRunInBackground(context))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
startServiceCompat(context);
|
startServiceCompat(context);
|
||||||
|
@ -36,4 +38,9 @@ public class BootReceiver extends BroadcastReceiver {
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean alwaysRunInBackground(Context context) {
|
||||||
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
return sp.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
package com.nutomic.syncthingandroid.receiver;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives network connection change intents and sends the wifi state to {@link SyncthingService}.
|
|
||||||
*/
|
|
||||||
public class NetworkReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
private static final String TAG = "NetworkReceiver";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!DeviceStateHolder.alwaysRunInBackground(context))
|
|
||||||
return;
|
|
||||||
|
|
||||||
updateNetworkStatus(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(16)
|
|
||||||
public static void updateNetworkStatus(Context context) {
|
|
||||||
ConnectivityManager cm = (ConnectivityManager)
|
|
||||||
context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
NetworkInfo ni = cm.getActiveNetworkInfo();
|
|
||||||
boolean isAllowedConnectionType = false;
|
|
||||||
if (ni == null) {
|
|
||||||
Log.v(TAG, "In flight mode");
|
|
||||||
// We still allow opening MainActivity and WebGuiActivity for local administration.
|
|
||||||
isAllowedConnectionType = true;
|
|
||||||
} else {
|
|
||||||
Log.v(TAG, "Not in flight mode");
|
|
||||||
boolean isWifi = ni.getType() == ConnectivityManager.TYPE_WIFI && ni.isConnected();
|
|
||||||
boolean isNetworkMetered = (Build.VERSION.SDK_INT >= 16) ? cm.isActiveNetworkMetered() : false;
|
|
||||||
isAllowedConnectionType = isWifi && !isNetworkMetered;
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
|
|
||||||
Intent intent = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED);
|
|
||||||
intent.putExtra(DeviceStateHolder.EXTRA_IS_ALLOWED_NETWORK_CONNECTION, isAllowedConnectionType);
|
|
||||||
lbm.sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.nutomic.syncthingandroid.receiver;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.service.DeviceStateHolder;
|
|
||||||
|
|
||||||
public class PowerSaveModeChangedReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
updatePowerSavingState(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void updatePowerSavingState(Context context) {
|
|
||||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
|
||||||
boolean isPowerSaveMode = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && pm.isPowerSaveMode();
|
|
||||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
|
|
||||||
Intent intent = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED);
|
|
||||||
intent.putExtra(DeviceStateHolder.EXTRA_IS_POWER_SAVING, isPowerSaveMode);
|
|
||||||
lbm.sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,251 +0,0 @@
|
||||||
package com.nutomic.syncthingandroid.service;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.wifi.WifiInfo;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
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.receiver.BatteryReceiver;
|
|
||||||
import com.nutomic.syncthingandroid.receiver.NetworkReceiver;
|
|
||||||
import com.nutomic.syncthingandroid.receiver.PowerSaveModeChangedReceiver;
|
|
||||||
import com.nutomic.syncthingandroid.service.ReceiverManager;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds information about the current wifi and charging state of the device.
|
|
||||||
*
|
|
||||||
* This information is actively read on instance creation, and then updated from intents
|
|
||||||
* that are passed with {@link #ACTION_DEVICE_STATE_CHANGED}.
|
|
||||||
*/
|
|
||||||
public class DeviceStateHolder implements SharedPreferences.OnSharedPreferenceChangeListener {
|
|
||||||
|
|
||||||
private static final String TAG = "DeviceStateHolder";
|
|
||||||
|
|
||||||
public static final String ACTION_DEVICE_STATE_CHANGED =
|
|
||||||
"com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.DEVICE_STATE_CHANGED";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intent extra containing a boolean saying whether wifi is connected or not.
|
|
||||||
*/
|
|
||||||
public static final String EXTRA_IS_ALLOWED_NETWORK_CONNECTION =
|
|
||||||
"com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.IS_ALLOWED_NETWORK_CONNECTION";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intent extra containging a boolean saying whether the device is
|
|
||||||
* charging or not (any power source).
|
|
||||||
*/
|
|
||||||
public static final String EXTRA_IS_CHARGING =
|
|
||||||
"com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.IS_CHARGING";
|
|
||||||
|
|
||||||
public static final String EXTRA_IS_POWER_SAVING =
|
|
||||||
"com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.IS_POWER_SAVING";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of "always_run_in_background" preference.
|
|
||||||
*/
|
|
||||||
public static boolean alwaysRunInBackground(Context context) {
|
|
||||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
return sp.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnDeviceStateChangedListener {
|
|
||||||
void onDeviceStateChanged(boolean shouldRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
private final LocalBroadcastManager mBroadcastManager;
|
|
||||||
@Inject SharedPreferences mPreferences;
|
|
||||||
|
|
||||||
private @Nullable DeviceStateChangedReceiver mDeviceStateChangedReceiver = null;
|
|
||||||
private ReceiverManager mReceiverManager;
|
|
||||||
|
|
||||||
// Those receivers are managed by {@link mReceiverManager}.
|
|
||||||
private NetworkReceiver mNetworkReceiver;
|
|
||||||
private BatteryReceiver mBatteryReceiver;
|
|
||||||
private PowerSaveModeChangedReceiver mPowerSaveModeChangedReceiver;
|
|
||||||
|
|
||||||
private boolean mIsAllowedConnectionType;
|
|
||||||
private String mWifiSsid;
|
|
||||||
private boolean mIsCharging;
|
|
||||||
private boolean mIsPowerSaving;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sending callback notifications through {@link OnDeviceStateChangedListener} is enabled if not null.
|
|
||||||
*/
|
|
||||||
private @Nullable OnDeviceStateChangedListener mOnDeviceStateChangedListener = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the result of the last call to {@link decideShouldRun}.
|
|
||||||
*/
|
|
||||||
private boolean lastDeterminedShouldRun = false;
|
|
||||||
|
|
||||||
public DeviceStateHolder(Context context, OnDeviceStateChangedListener listener) {
|
|
||||||
Log.v(TAG, "Created new instance");
|
|
||||||
((SyncthingApp) context.getApplicationContext()).component().inject(this);
|
|
||||||
mContext = context;
|
|
||||||
mPreferences.registerOnSharedPreferenceChangeListener(this);
|
|
||||||
mOnDeviceStateChangedListener = listener;
|
|
||||||
|
|
||||||
mDeviceStateChangedReceiver = new DeviceStateChangedReceiver();
|
|
||||||
mBroadcastManager = LocalBroadcastManager.getInstance(mContext);
|
|
||||||
mBroadcastManager.registerReceiver(mDeviceStateChangedReceiver, new IntentFilter(ACTION_DEVICE_STATE_CHANGED));
|
|
||||||
registerChildReceivers();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() {
|
|
||||||
Log.v(TAG, "Shutting down");
|
|
||||||
mPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
|
||||||
mReceiverManager.unregisterAllReceivers(mContext);
|
|
||||||
if (mDeviceStateChangedReceiver != null) {
|
|
||||||
mBroadcastManager.unregisterReceiver(mDeviceStateChangedReceiver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
|
||||||
List<String> watched = Lists.newArrayList(Constants.PREF_SYNC_ONLY_CHARGING,
|
|
||||||
Constants.PREF_SYNC_ONLY_WIFI, Constants.PREF_RESPECT_BATTERY_SAVING,
|
|
||||||
Constants.PREF_SYNC_ONLY_WIFI_SSIDS);
|
|
||||||
if (watched.contains(key)) {
|
|
||||||
mReceiverManager.unregisterAllReceivers(mContext);
|
|
||||||
registerChildReceivers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerChildReceivers() {
|
|
||||||
boolean incomingBroadcastEventsExpected = false;
|
|
||||||
|
|
||||||
if (mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_WIFI, false)) {
|
|
||||||
Log.i(TAG, "Creating NetworkReceiver");
|
|
||||||
NetworkReceiver.updateNetworkStatus(mContext);
|
|
||||||
mNetworkReceiver = new NetworkReceiver();
|
|
||||||
ReceiverManager.registerReceiver(mContext, mNetworkReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
|
||||||
incomingBroadcastEventsExpected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_CHARGING, false)) {
|
|
||||||
Log.i(TAG, "Creating BatteryReceiver");
|
|
||||||
BatteryReceiver.updateInitialChargingStatus(mContext);
|
|
||||||
mBatteryReceiver = new BatteryReceiver();
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(Intent.ACTION_POWER_CONNECTED);
|
|
||||||
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
|
|
||||||
ReceiverManager.registerReceiver(mContext, mBatteryReceiver, filter);
|
|
||||||
incomingBroadcastEventsExpected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
|
|
||||||
mPreferences.getBoolean(Constants.PREF_RESPECT_BATTERY_SAVING, true)) {
|
|
||||||
Log.i(TAG, "Creating PowerSaveModeChangedReceiver");
|
|
||||||
PowerSaveModeChangedReceiver.updatePowerSavingState(mContext);
|
|
||||||
mPowerSaveModeChangedReceiver = new PowerSaveModeChangedReceiver();
|
|
||||||
ReceiverManager.registerReceiver(mContext, mPowerSaveModeChangedReceiver,
|
|
||||||
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
|
|
||||||
incomingBroadcastEventsExpected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no broadcast messages can be received as we didn't register an emitter,
|
|
||||||
// force an initial decision to be made.
|
|
||||||
if (!incomingBroadcastEventsExpected) {
|
|
||||||
updateShouldRunDecision();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DeviceStateChangedReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
mIsAllowedConnectionType =
|
|
||||||
intent.getBooleanExtra(EXTRA_IS_ALLOWED_NETWORK_CONNECTION, mIsAllowedConnectionType);
|
|
||||||
mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging);
|
|
||||||
mIsPowerSaving = intent.getBooleanExtra(EXTRA_IS_POWER_SAVING, mIsPowerSaving);
|
|
||||||
updateShouldRunDecision();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateWifiSsid() {
|
|
||||||
mWifiSsid = null;
|
|
||||||
WifiManager wifiManager =
|
|
||||||
(WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
|
||||||
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
|
||||||
// May be null, if WiFi has been turned off in meantime.
|
|
||||||
if (wifiInfo != null) {
|
|
||||||
mWifiSsid = wifiInfo.getSSID();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateShouldRunDecision() {
|
|
||||||
// Check if the current conditions changed the result of decideShouldRun()
|
|
||||||
// compared to the last determined result.
|
|
||||||
boolean newShouldRun = decideShouldRun();
|
|
||||||
if (newShouldRun != lastDeterminedShouldRun) {
|
|
||||||
if (mOnDeviceStateChangedListener != null) {
|
|
||||||
mOnDeviceStateChangedListener.onDeviceStateChanged(newShouldRun);
|
|
||||||
}
|
|
||||||
lastDeterminedShouldRun = newShouldRun;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if Syncthing should currently run.
|
|
||||||
*/
|
|
||||||
private boolean decideShouldRun() {
|
|
||||||
Log.v(TAG, "State updated: IsAllowedConnectionType: " + mIsAllowedConnectionType +
|
|
||||||
", IsCharging: " + mIsCharging + ", IsPowerSaving: " + mIsPowerSaving);
|
|
||||||
|
|
||||||
boolean prefRespectPowerSaving = mPreferences.getBoolean(Constants.PREF_RESPECT_BATTERY_SAVING, true);
|
|
||||||
if (prefRespectPowerSaving && mIsPowerSaving)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (alwaysRunInBackground(mContext)) {
|
|
||||||
boolean prefStopMobileData = mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_WIFI, false);
|
|
||||||
boolean prefStopNotCharging = mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_CHARGING, false);
|
|
||||||
|
|
||||||
updateWifiSsid();
|
|
||||||
if (prefStopMobileData && !isWhitelistedWifiConnection())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (prefStopNotCharging && !mIsCharging)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isWhitelistedWifiConnection() {
|
|
||||||
boolean wifiConnected = mIsAllowedConnectionType;
|
|
||||||
if (wifiConnected) {
|
|
||||||
Set<String> ssids = mPreferences.getStringSet(Constants.PREF_SYNC_ONLY_WIFI_SSIDS, new HashSet<>());
|
|
||||||
if (ssids.isEmpty()) {
|
|
||||||
Log.d(TAG, "All SSIDs allowed for syncing");
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (mWifiSsid != null && ssids.contains(mWifiSsid)) {
|
|
||||||
Log.d(TAG, "SSID [" + mWifiSsid + "] found in whitelist: " + ssids);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "SSID [" + mWifiSsid + "] unknown or not whitelisted, disallowing sync.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,6 +8,7 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -17,6 +18,7 @@ import com.nutomic.syncthingandroid.SyncthingApp;
|
||||||
import com.nutomic.syncthingandroid.activities.FirstStartActivity;
|
import com.nutomic.syncthingandroid.activities.FirstStartActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.LogActivity;
|
import com.nutomic.syncthingandroid.activities.LogActivity;
|
||||||
import com.nutomic.syncthingandroid.activities.MainActivity;
|
import com.nutomic.syncthingandroid.activities.MainActivity;
|
||||||
|
import com.nutomic.syncthingandroid.service.Constants;
|
||||||
import com.nutomic.syncthingandroid.service.SyncthingService.State;
|
import com.nutomic.syncthingandroid.service.SyncthingService.State;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -96,7 +98,7 @@ public class NotificationHandler {
|
||||||
// is not killed, and we don't miss wifi/charging events.
|
// is not killed, and we don't miss wifi/charging events.
|
||||||
// On Android 8, this behaviour is mandatory to receive broadcasts.
|
// On Android 8, this behaviour is mandatory to receive broadcasts.
|
||||||
// https://stackoverflow.com/a/44505719/1837158
|
// https://stackoverflow.com/a/44505719/1837158
|
||||||
boolean foreground = DeviceStateHolder.alwaysRunInBackground(mContext);
|
boolean foreground = mPreferences.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
||||||
|
|
||||||
// Foreground priority requires a notification so this ensures that we either have a
|
// Foreground priority requires a notification so this ensures that we either have a
|
||||||
// "default" or "low_priority" notification, but not "none".
|
// "default" or "low_priority" notification, but not "none".
|
||||||
|
@ -158,7 +160,7 @@ public class NotificationHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancelPersistentNotification(SyncthingService service) {
|
public void cancelPersistentNotification(SyncthingService service) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && DeviceStateHolder.alwaysRunInBackground(mContext))
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && alwaysRunInBackground())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
service.stopForeground(false);
|
service.stopForeground(false);
|
||||||
|
@ -278,4 +280,9 @@ public class NotificationHandler {
|
||||||
}
|
}
|
||||||
mNotificationManager.notify(ID_STOP_BACKGROUND_WARNING, nb.build());
|
mNotificationManager.notify(ID_STOP_BACKGROUND_WARNING, nb.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean alwaysRunInBackground() {
|
||||||
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
return sp.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,268 @@
|
||||||
|
package com.nutomic.syncthingandroid.service;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.wifi.WifiInfo;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.os.BatteryManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
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 java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds information about the current wifi and charging state of the device.
|
||||||
|
*
|
||||||
|
* This information is actively read on instance creation, and then updated from intents
|
||||||
|
* that are passed with {@link #ACTION_DEVICE_STATE_CHANGED}.
|
||||||
|
*/
|
||||||
|
public class RunConditionMonitor implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
|
private static final String TAG = "RunConditionMonitor";
|
||||||
|
|
||||||
|
public interface OnRunConditionChangedListener {
|
||||||
|
void onRunConditionChanged(boolean shouldRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
@Inject SharedPreferences mPreferences;
|
||||||
|
private ReceiverManager mReceiverManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sending callback notifications through {@link OnDeviceStateChangedListener} is enabled if not null.
|
||||||
|
*/
|
||||||
|
private @Nullable OnRunConditionChangedListener mOnRunConditionChangedListener = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the result of the last call to {@link decideShouldRun}.
|
||||||
|
*/
|
||||||
|
private boolean lastDeterminedShouldRun = false;
|
||||||
|
|
||||||
|
public RunConditionMonitor(Context context, OnRunConditionChangedListener listener) {
|
||||||
|
Log.v(TAG, "Created new instance");
|
||||||
|
((SyncthingApp) context.getApplicationContext()).component().inject(this);
|
||||||
|
mContext = context;
|
||||||
|
mPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||||
|
mOnRunConditionChangedListener = listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register broadcast receivers.
|
||||||
|
*/
|
||||||
|
// NetworkReceiver
|
||||||
|
ReceiverManager.registerReceiver(mContext, new NetworkReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||||
|
|
||||||
|
// BatteryReceiver
|
||||||
|
IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(Intent.ACTION_POWER_CONNECTED);
|
||||||
|
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
|
||||||
|
ReceiverManager.registerReceiver(mContext, new BatteryReceiver(), filter);
|
||||||
|
|
||||||
|
// PowerSaveModeChangedReceiver
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
ReceiverManager.registerReceiver(mContext,
|
||||||
|
new PowerSaveModeChangedReceiver(),
|
||||||
|
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initially determine if syncthing should run under current circumstances.
|
||||||
|
updateShouldRunDecision();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
Log.v(TAG, "Shutting down");
|
||||||
|
mPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
|
mReceiverManager.unregisterAllReceivers(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
List<String> watched = Lists.newArrayList(
|
||||||
|
Constants.PREF_SYNC_ONLY_CHARGING,
|
||||||
|
Constants.PREF_SYNC_ONLY_WIFI, Constants.PREF_RESPECT_BATTERY_SAVING,
|
||||||
|
Constants.PREF_SYNC_ONLY_WIFI_SSIDS);
|
||||||
|
if (watched.contains(key)) {
|
||||||
|
// Force a re-evaluation of which run conditions apply according to the changed prefs.
|
||||||
|
updateShouldRunDecision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BatteryReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())
|
||||||
|
|| Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
|
||||||
|
updateShouldRunDecision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NetworkReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
|
||||||
|
updateShouldRunDecision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PowerSaveModeChangedReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
|
||||||
|
updateShouldRunDecision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateShouldRunDecision() {
|
||||||
|
// Check 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);
|
||||||
|
}
|
||||||
|
lastDeterminedShouldRun = newShouldRun;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if Syncthing should currently run.
|
||||||
|
*/
|
||||||
|
private boolean decideShouldRun() {
|
||||||
|
// Get run conditions preferences.
|
||||||
|
boolean prefAlwaysRunInBackground = mPreferences.getBoolean(Constants.PREF_ALWAYS_RUN_IN_BACKGROUND, false);
|
||||||
|
boolean prefRespectPowerSaving = mPreferences.getBoolean(Constants.PREF_RESPECT_BATTERY_SAVING, true);
|
||||||
|
boolean prefRunOnlyOnWifi= mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_WIFI, false);
|
||||||
|
boolean prefRunOnlyWhenCharging = mPreferences.getBoolean(Constants.PREF_SYNC_ONLY_CHARGING, false);
|
||||||
|
Set<String> whitelistedWifiSsids = mPreferences.getStringSet(Constants.PREF_SYNC_ONLY_WIFI_SSIDS, new HashSet<>());
|
||||||
|
boolean prefWifiWhitelistEnabled = !whitelistedWifiSsids.isEmpty();
|
||||||
|
|
||||||
|
// Power saving
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
if (prefRespectPowerSaving && isPowerSaving()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always run in background
|
||||||
|
if (!prefAlwaysRunInBackground) {
|
||||||
|
/**
|
||||||
|
* User did not specify run conditions in the options.
|
||||||
|
* The app is displaying a foreground activity and syncthing should run.
|
||||||
|
*/
|
||||||
|
Log.v(TAG, "decideShouldRun: !prefAlwaysRunInBackground");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run only when charging.
|
||||||
|
if (prefRunOnlyWhenCharging && !isCharging()) {
|
||||||
|
Log.v(TAG, "decideShouldRun: prefRunOnlyWhenCharging && !isCharging");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run only on wifi.
|
||||||
|
if (prefRunOnlyOnWifi && !isWifiOrEthernetConnection()) {
|
||||||
|
// Not on wifi.
|
||||||
|
Log.v(TAG, "decideShouldRun: prefRunOnlyOnWifi && !isWifiOrEthernetConnection");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run only on whitelisted wifi ssids.
|
||||||
|
if (prefRunOnlyOnWifi && prefWifiWhitelistEnabled) {
|
||||||
|
// Wifi connection detected. Wifi ssid whitelist enabled.
|
||||||
|
Log.v(TAG, "decideShouldRun: prefRunOnlyOnWifi && prefWifiWhitelistEnabled");
|
||||||
|
return isWifiConnectionWhitelisted(whitelistedWifiSsids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respect power saving, device is not in power-save mode.
|
||||||
|
* Always run in background is the only pref that is enabled.
|
||||||
|
* Run only when charging, charging.
|
||||||
|
* Run only on wifi, wifi connection detected, wifi ssid whitelist disabled.
|
||||||
|
*/
|
||||||
|
Log.v(TAG, "decideShouldRun: return true");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions for run condition information retrieval.
|
||||||
|
*/
|
||||||
|
private boolean isCharging() {
|
||||||
|
Intent batteryIntent = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||||
|
int status = batteryIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
|
||||||
|
return status == BatteryManager.BATTERY_STATUS_CHARGING ||
|
||||||
|
status == BatteryManager.BATTERY_STATUS_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(21)
|
||||||
|
private boolean isPowerSaving() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
Log.e(TAG, "isPowerSaving may not be called on pre-lollipop android versions.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||||
|
if (powerManager == null) {
|
||||||
|
Log.e(TAG, "getSystemService(POWER_SERVICE) unexpectedly returned NULL.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return powerManager.isPowerSaveMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWifiOrEthernetConnection() {
|
||||||
|
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo ni = cm.getActiveNetworkInfo();
|
||||||
|
if (ni == null) {
|
||||||
|
// In flight mode.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ni.isConnected()) {
|
||||||
|
// No network connection.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (ni.getType()) {
|
||||||
|
case ConnectivityManager.TYPE_WIFI:
|
||||||
|
case ConnectivityManager.TYPE_WIMAX:
|
||||||
|
case ConnectivityManager.TYPE_ETHERNET:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWifiConnectionWhitelisted(Set<String> whitelistedSsids) {
|
||||||
|
WifiManager wifiManager = (WifiManager) mContext.getApplicationContext()
|
||||||
|
.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
||||||
|
if (wifiInfo == null) {
|
||||||
|
// May be null, if wifi has been turned off in the meantime.
|
||||||
|
Log.d(TAG, "isWifiConnectionWhitelisted: SSID unknown due to wifiInfo == null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String wifiSsid = wifiInfo.getSSID();
|
||||||
|
if (wifiSsid == null) {
|
||||||
|
Log.w(TAG, "isWifiConnectionWhitelisted: Got null SSID. Try to enable android location service.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return whitelistedSsids.contains(wifiSsid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -119,7 +119,7 @@ public class SyncthingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the service with State.DISABLED as {@link DeviceStateHolder} will
|
* Initialize the service with State.DISABLED as {@link RunConditionMonitor} will
|
||||||
* send an update if we should run the binary after it got instantiated in
|
* send an update if we should run the binary after it got instantiated in
|
||||||
* {@link onStartCommand}.
|
* {@link onStartCommand}.
|
||||||
*/
|
*/
|
||||||
|
@ -129,7 +129,7 @@ public class SyncthingService extends Service {
|
||||||
private @Nullable PollWebGuiAvailableTask mPollWebGuiAvailableTask = null;
|
private @Nullable PollWebGuiAvailableTask mPollWebGuiAvailableTask = null;
|
||||||
private @Nullable RestApi mApi = null;
|
private @Nullable RestApi mApi = null;
|
||||||
private @Nullable EventProcessor mEventProcessor = null;
|
private @Nullable EventProcessor mEventProcessor = null;
|
||||||
private @Nullable DeviceStateHolder mDeviceStateHolder = null;
|
private @Nullable RunConditionMonitor mRunConditionMonitor = null;
|
||||||
private @Nullable SyncthingRunnable mSyncthingRunnable = null;
|
private @Nullable SyncthingRunnable mSyncthingRunnable = null;
|
||||||
private StartupTask mStartupTask = null;
|
private StartupTask mStartupTask = null;
|
||||||
private Thread mSyncthingRunnableThread = null;
|
private Thread mSyncthingRunnableThread = null;
|
||||||
|
@ -184,9 +184,7 @@ public class SyncthingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles intents, either {@link #ACTION_RESTART}, or intents having
|
* Handles intent actions, e.g. {@link #ACTION_RESTART}
|
||||||
* {@link DeviceStateHolder#EXTRA_IS_ALLOWED_NETWORK_CONNECTION} or
|
|
||||||
* {@link DeviceStateHolder#EXTRA_IS_CHARGING} (which are handled by {@link DeviceStateHolder}.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
@ -203,7 +201,7 @@ public class SyncthingService extends Service {
|
||||||
/**
|
/**
|
||||||
* Send current service state to listening endpoints.
|
* Send current service state to listening endpoints.
|
||||||
* This is required that components know about the service State.DISABLED
|
* This is required that components know about the service State.DISABLED
|
||||||
* if DeviceStateHolder does not send a "shouldRun = true" callback
|
* if RunConditionMonitor does not send a "shouldRun = true" callback
|
||||||
* to start the binary according to preferences shortly after its creation.
|
* to start the binary according to preferences shortly after its creation.
|
||||||
* See {@link mLastDeterminedShouldRun} defaulting to "false".
|
* See {@link mLastDeterminedShouldRun} defaulting to "false".
|
||||||
*/
|
*/
|
||||||
|
@ -212,14 +210,14 @@ public class SyncthingService extends Service {
|
||||||
onServiceStateChange(mCurrentState);
|
onServiceStateChange(mCurrentState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mDeviceStateHolder == null) {
|
if (mRunConditionMonitor == null) {
|
||||||
/**
|
/**
|
||||||
* Instantiate the run condition monitor on first onStartCommand and
|
* Instantiate the run condition monitor on first onStartCommand and
|
||||||
* enable callback on run condition change affecting the final decision to
|
* enable callback on run condition change affecting the final decision to
|
||||||
* run/terminate syncthing. After initial run conditions are collected
|
* run/terminate syncthing. After initial run conditions are collected
|
||||||
* the first decision is sent to {@link onUpdatedShouldRunDecision}.
|
* the first decision is sent to {@link onUpdatedShouldRunDecision}.
|
||||||
*/
|
*/
|
||||||
mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this, this::onUpdatedShouldRunDecision);
|
mRunConditionMonitor = new RunConditionMonitor(SyncthingService.this, this::onUpdatedShouldRunDecision);
|
||||||
}
|
}
|
||||||
mNotificationHandler.updatePersistentNotification(this);
|
mNotificationHandler.updatePersistentNotification(this);
|
||||||
|
|
||||||
|
@ -239,7 +237,7 @@ public class SyncthingService extends Service {
|
||||||
launchStartupTask();
|
launchStartupTask();
|
||||||
});
|
});
|
||||||
} else if (ACTION_REFRESH_NETWORK_INFO.equals(intent.getAction())) {
|
} else if (ACTION_REFRESH_NETWORK_INFO.equals(intent.getAction())) {
|
||||||
mDeviceStateHolder.updateShouldRunDecision();
|
mRunConditionMonitor.updateShouldRunDecision();
|
||||||
} else if (ACTION_IGNORE_DEVICE.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
|
} else if (ACTION_IGNORE_DEVICE.equals(intent.getAction()) && mCurrentState == State.ACTIVE) {
|
||||||
// mApi is not null due to State.ACTIVE
|
// mApi is not null due to State.ACTIVE
|
||||||
mApi.ignoreDevice(intent.getStringExtra(EXTRA_DEVICE_ID));
|
mApi.ignoreDevice(intent.getStringExtra(EXTRA_DEVICE_ID));
|
||||||
|
@ -255,7 +253,7 @@ public class SyncthingService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After run conditions monitored by {@link DeviceStateHolder} changed and
|
* After run conditions monitored by {@link RunConditionMonitor} changed and
|
||||||
* it had an influence on the decision to run/terminate syncthing, this
|
* it had an influence on the decision to run/terminate syncthing, this
|
||||||
* function is called to notify this class to run/terminate the syncthing binary.
|
* function is called to notify this class to run/terminate the syncthing binary.
|
||||||
* {@link #onServiceStateChange} is called while applying the decision change.
|
* {@link #onServiceStateChange} is called while applying the decision change.
|
||||||
|
@ -439,17 +437,17 @@ public class SyncthingService extends Service {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the native binary.
|
* Stops the native binary.
|
||||||
* Shuts down DeviceStateHolder instance.
|
* Shuts down RunConditionMonitor instance.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
Log.v(TAG, "onDestroy");
|
Log.v(TAG, "onDestroy");
|
||||||
if (mDeviceStateHolder != null) {
|
if (mRunConditionMonitor != null) {
|
||||||
/**
|
/**
|
||||||
* Shut down the OnDeviceStateChangedListener so we won't get interrupted by run
|
* Shut down the OnDeviceStateChangedListener so we won't get interrupted by run
|
||||||
* condition events that occur during shutdown.
|
* condition events that occur during shutdown.
|
||||||
*/
|
*/
|
||||||
mDeviceStateHolder.shutdown();
|
mRunConditionMonitor.shutdown();
|
||||||
}
|
}
|
||||||
if (mStoragePermissionGranted) {
|
if (mStoragePermissionGranted) {
|
||||||
synchronized (mStateLock) {
|
synchronized (mStateLock) {
|
||||||
|
|
Loading…
Reference in a new issue