Rework run conditions (fixes #540)

This commit is contained in:
Felix Ableitner 2017-09-26 23:13:12 +09:00
parent 42a87031f1
commit 5c97251ffa
7 changed files with 67 additions and 78 deletions

View File

@ -42,29 +42,13 @@ public class DeviceStateHolderTest {
@Test @Test
public void testWifiConnected() { public void testWifiConnected() {
Intent i = new Intent(); Intent i = new Intent();
i.putExtra(DeviceStateHolder.EXTRA_HAS_WIFI, false); i.putExtra(DeviceStateHolder.EXTRA_IS_ALLOWED_NETWORK_CONNECTION, false);
mReceiver.update(i); mReceiver.update(i);
Assert.assertFalse(mReceiver.isWifiConnected()); Assert.assertFalse(mReceiver.isAllowedNetworkConnection());
i.putExtra(DeviceStateHolder.EXTRA_HAS_WIFI, true); i.putExtra(DeviceStateHolder.EXTRA_IS_ALLOWED_NETWORK_CONNECTION, true);
mReceiver.update(i); mReceiver.update(i);
Assert.assertTrue(mReceiver.isWifiConnected()); Assert.assertTrue(mReceiver.isAllowedNetworkConnection());
}
@Test
public void testonReceiveInitialChargingState() {
Intent i = new Intent();
mReceiver.onReceive(mContext, i);
Assert.assertFalse(mReceiver.isCharging());
Assert.assertEquals(mContext.getLastUnregistered(), mReceiver);
i.putExtra(BatteryManager.EXTRA_PLUGGED, 0);
mReceiver.onReceive(mContext, i);
Assert.assertFalse(mReceiver.isCharging());
i.putExtra(BatteryManager.EXTRA_PLUGGED, 1);
mReceiver.onReceive(mContext, i);
Assert.assertTrue(mReceiver.isCharging());
} }
} }

View File

@ -55,7 +55,7 @@ public class NetworkReceiverTest {
Intent receivedIntent = mContext.getReceivedIntents().get(0); Intent receivedIntent = mContext.getReceivedIntents().get(0);
Assert.assertEquals(SyncthingService.class.getName(), receivedIntent.getComponent().getClassName()); Assert.assertEquals(SyncthingService.class.getName(), receivedIntent.getComponent().getClassName());
Assert.assertNull(receivedIntent.getAction()); Assert.assertNull(receivedIntent.getAction());
Assert.assertTrue(receivedIntent.hasExtra(DeviceStateHolder.EXTRA_HAS_WIFI)); Assert.assertTrue(receivedIntent.hasExtra(DeviceStateHolder.EXTRA_IS_ALLOWED_NETWORK_CONNECTION));
mContext.clearReceivedIntents(); mContext.clearReceivedIntents();
} }

View File

@ -73,9 +73,8 @@ public abstract class StateDialogActivity extends SyncthingActivity {
.setNegativeButton(R.string.exit, .setNegativeButton(R.string.exit,
(dialogInterface, i) -> ActivityCompat.finishAffinity(this) (dialogInterface, i) -> ActivityCompat.finishAffinity(this)
) )
.setOnCancelListener(dialogInterface -> ActivityCompat.finishAffinity(this)) .setCancelable(false)
.show(); .show();
mDisabledDialog.setCanceledOnTouchOutside(false);
} }
private void dismissDisabledDialog() { private void dismissDisabledDialog() {

View File

@ -3,6 +3,8 @@ 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.IntentFilter;
import android.os.BatteryManager;
import android.util.Log; import android.util.Log;
import com.nutomic.syncthingandroid.service.DeviceStateHolder; import com.nutomic.syncthingandroid.service.DeviceStateHolder;
@ -13,8 +15,6 @@ import com.nutomic.syncthingandroid.service.SyncthingService;
*/ */
public class BatteryReceiver extends BroadcastReceiver { public class BatteryReceiver extends BroadcastReceiver {
private static final String TAG = "BatteryReceiver";
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (!Intent.ACTION_POWER_CONNECTED.equals(intent.getAction()) if (!Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())
@ -25,10 +25,23 @@ public class BatteryReceiver extends BroadcastReceiver {
return; return;
boolean isCharging = Intent.ACTION_POWER_CONNECTED.equals(intent.getAction()); boolean isCharging = Intent.ACTION_POWER_CONNECTED.equals(intent.getAction());
Log.v(TAG, "Received charger " + (isCharging ? "connected" : "disconnected") + " event");
Intent i = new Intent(context, SyncthingService.class); Intent i = new Intent(context, SyncthingService.class);
i.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging); i.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
context.startService(i); context.startService(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;
Intent intent = new Intent(context, SyncthingService.class);
intent.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
context.startService(intent);
}
} }

View File

@ -1,10 +1,12 @@
package com.nutomic.syncthingandroid.receiver; package com.nutomic.syncthingandroid.receiver;
import android.annotation.TargetApi;
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.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Build;
import android.util.Log; import android.util.Log;
import com.nutomic.syncthingandroid.service.DeviceStateHolder; import com.nutomic.syncthingandroid.service.DeviceStateHolder;
@ -25,14 +27,22 @@ public class NetworkReceiver extends BroadcastReceiver {
if (!SyncthingService.alwaysRunInBackground(context)) if (!SyncthingService.alwaysRunInBackground(context))
return; return;
ConnectivityManager cm = updateNetworkStatus(context);
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); }
@TargetApi(16)
public static void updateNetworkStatus(Context context) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo(); NetworkInfo ni = cm.getActiveNetworkInfo();
boolean isWifiConnected = ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI && ni.isConnected(); boolean isOffline = ni == null;
Log.v(TAG, "Received wifi " + (isWifiConnected ? "connected" : "disconnected") + " event"); boolean isWifi = ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI && ni.isConnected();
Intent i = new Intent(context, SyncthingService.class); boolean isNetworkMetered = (Build.VERSION.SDK_INT >= 16) ? cm.isActiveNetworkMetered() : false;
i.putExtra(DeviceStateHolder.EXTRA_HAS_WIFI, isWifiConnected); boolean isAllowedConnection = isOffline || (isWifi && !isNetworkMetered);
context.startService(i);
Intent intent = new Intent(context, SyncthingService.class);
intent.putExtra(DeviceStateHolder.EXTRA_IS_ALLOWED_NETWORK_CONNECTION, isAllowedConnection);
context.startService(intent);
} }
} }

View File

@ -1,37 +1,37 @@
package com.nutomic.syncthingandroid.service; package com.nutomic.syncthingandroid.service;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Build; import android.os.Build;
import android.os.PowerManager; import android.os.PowerManager;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import com.nutomic.syncthingandroid.receiver.BatteryReceiver;
import com.nutomic.syncthingandroid.receiver.NetworkReceiver;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
* Holds information about the current wifi and charging state of the device. * Holds information about the current wifi and charging state of the device.
* <p/> *
* This information is actively read on construction, and then updated from intents that are passed * This information is actively read on construction, and then updated from intents that are passed
* to {@link #update(android.content.Intent)}. * to {@link #update(android.content.Intent)}.
*/ */
public class DeviceStateHolder extends BroadcastReceiver { public class DeviceStateHolder {
private static final String TAG = "DeviceStateHolder"; private static final String TAG = "DeviceStateHolder";
/** /**
* Intent extra containing a boolean saying whether wifi is connected or not. * Intent extra containing a boolean saying whether wifi is connected or not.
*/ */
public static final String EXTRA_HAS_WIFI = public static final String EXTRA_IS_ALLOWED_NETWORK_CONNECTION =
"com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.HAS_WIFI"; "com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.IS_ALLOWED_NETWORK_CONNECTION";
/** /**
* Intent extra containging a boolean saying whether the device is * Intent extra containging a boolean saying whether the device is
@ -41,50 +41,36 @@ public class DeviceStateHolder extends BroadcastReceiver {
"com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.IS_CHARGING"; "com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.IS_CHARGING";
private final Context mContext; private final Context mContext;
private final SharedPreferences mPreferences;
private boolean mIsWifiConnected = false; private boolean mIsAllowedNetworkConnection = false;
private String mWifiSsid; private String mWifiSsid;
private boolean mIsCharging = false; private boolean mIsCharging = false;
public DeviceStateHolder(Context context) { public DeviceStateHolder(Context context) {
mContext = context; mContext = context;
ConnectivityManager cm = (ConnectivityManager) mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
mIsWifiConnected = ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI && ni.isConnected();
if (android.os.Build.VERSION.SDK_INT >= 16 && cm.isActiveNetworkMetered())
mIsWifiConnected = false;
if (mIsWifiConnected) {
updateWifiSsid();
}
}
/** BatteryReceiver.updateInitialChargingStatus(mContext);
* Receiver for {@link Intent#ACTION_BATTERY_CHANGED}, which is used to determine the initial NetworkReceiver.updateNetworkStatus(mContext);
* charging state.
*/
@Override
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
int status = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
mIsCharging = status != 0;
} }
public boolean isCharging() { public boolean isCharging() {
return mIsCharging; return mIsCharging;
} }
public boolean isWifiConnected() { public boolean isAllowedNetworkConnection() {
return mIsWifiConnected; return mIsAllowedNetworkConnection;
} }
public void update(Intent intent) { public void update(Intent intent) {
mIsWifiConnected = intent.getBooleanExtra(EXTRA_HAS_WIFI, mIsWifiConnected); mIsAllowedNetworkConnection =
intent.getBooleanExtra(EXTRA_IS_ALLOWED_NETWORK_CONNECTION, mIsAllowedNetworkConnection);
mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging); mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging);
Log.i(TAG, "State updated, allowed network connection: " + mIsAllowedNetworkConnection +
", charging: " + mIsCharging);
if (mIsWifiConnected) { if (mIsAllowedNetworkConnection) {
updateWifiSsid(); updateWifiSsid();
} else { } else {
mWifiSsid = null; mWifiSsid = null;
@ -110,17 +96,16 @@ public class DeviceStateHolder extends BroadcastReceiver {
* Determines if Syncthing should currently run. * Determines if Syncthing should currently run.
*/ */
public boolean shouldRun() { public boolean shouldRun() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
prefs.getBoolean("respect_battery_saving", true) && mPreferences.getBoolean("respect_battery_saving", true) &&
pm.isPowerSaveMode()) { pm.isPowerSaveMode()) {
return false; return false;
} }
else if (SyncthingService.alwaysRunInBackground(mContext)) { else if (SyncthingService.alwaysRunInBackground(mContext)) {
// Check wifi/charging state against preferences and start if ok. // Check wifi/charging state against preferences and start if ok.
boolean prefStopMobileData = prefs.getBoolean(SyncthingService.PREF_SYNC_ONLY_WIFI, false); boolean prefStopMobileData = mPreferences.getBoolean(SyncthingService.PREF_SYNC_ONLY_WIFI, false);
boolean prefStopNotCharging = prefs.getBoolean(SyncthingService.PREF_SYNC_ONLY_CHARGING, false); boolean prefStopNotCharging = mPreferences.getBoolean(SyncthingService.PREF_SYNC_ONLY_CHARGING, false);
return (isCharging() || !prefStopNotCharging) && return (isCharging() || !prefStopNotCharging) &&
(!prefStopMobileData || isAllowedWifiConnected()); (!prefStopMobileData || isAllowedWifiConnected());
@ -131,10 +116,9 @@ public class DeviceStateHolder extends BroadcastReceiver {
} }
private boolean isAllowedWifiConnected() { private boolean isAllowedWifiConnected() {
boolean wifiConnected = isWifiConnected(); boolean wifiConnected = isAllowedNetworkConnection();
if (wifiConnected) { if (wifiConnected) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); Set<String> ssids = mPreferences.getStringSet(SyncthingService.PREF_SYNC_ONLY_WIFI_SSIDS, new HashSet<>());
Set<String> ssids = sp.getStringSet(SyncthingService.PREF_SYNC_ONLY_WIFI_SSIDS, new HashSet<>());
if (ssids.isEmpty()) { if (ssids.isEmpty()) {
Log.d(TAG, "All SSIDs allowed for syncing"); Log.d(TAG, "All SSIDs allowed for syncing");
return true; return true;

View File

@ -167,8 +167,8 @@ public class SyncthingService extends Service implements
/** /**
* Handles intents, either {@link #ACTION_RESTART}, or intents having * Handles intents, either {@link #ACTION_RESTART}, or intents having
* {@link DeviceStateHolder#EXTRA_HAS_WIFI} or {@link DeviceStateHolder#EXTRA_IS_CHARGING} * {@link DeviceStateHolder#EXTRA_IS_ALLOWED_NETWORK_CONNECTION} or
* (which are handled by {@link DeviceStateHolder}. * {@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) {
@ -184,7 +184,7 @@ public class SyncthingService extends Service implements
new SyncthingRunnable(this, SyncthingRunnable.Command.reset).run(); new SyncthingRunnable(this, SyncthingRunnable.Command.reset).run();
mCurrentState = State.INIT; mCurrentState = State.INIT;
updateState(); updateState();
} else if (mCurrentState != State.INIT) { } else {
mDeviceStateHolder.update(intent); mDeviceStateHolder.update(intent);
updateState(); updateState();
} }
@ -309,7 +309,6 @@ public class SyncthingService extends Service implements
PRNGFixes.apply(); PRNGFixes.apply();
mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this); mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this);
registerReceiver(mDeviceStateHolder, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
registerReceiver(mPowerSaveModeChangedReceiver, registerReceiver(mPowerSaveModeChangedReceiver,
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));