Refactor DeviceStateHolder and receivers

This commit is contained in:
Felix Ableitner 2017-10-02 15:21:11 +09:00
parent 9ad854defb
commit be1be9746e
5 changed files with 121 additions and 53 deletions

View File

@ -5,6 +5,7 @@ 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;
@ -24,9 +25,13 @@ public class BatteryReceiver extends BroadcastReceiver {
return;
boolean isCharging = Intent.ACTION_POWER_CONNECTED.equals(intent.getAction());
Intent i = new Intent(context, SyncthingService.class);
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
Intent i = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED);
i.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
context.startService(i);
lbm.sendBroadcast(i);
// Make sure service is running.
context.startService(new Intent(context, SyncthingService.class));
}
/**
@ -38,9 +43,10 @@ public class BatteryReceiver extends BroadcastReceiver {
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
Intent intent = new Intent(context, SyncthingService.class);
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
Intent intent = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED);
intent.putExtra(DeviceStateHolder.EXTRA_IS_CHARGING, isCharging);
context.startService(intent);
lbm.sendBroadcast(intent);
}
}

View File

@ -7,6 +7,8 @@ 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;
@ -37,9 +39,13 @@ public class NetworkReceiver extends BroadcastReceiver {
boolean isNetworkMetered = (Build.VERSION.SDK_INT >= 16) ? cm.isActiveNetworkMetered() : false;
boolean isAllowedConnection = isOffline || (isWifi && !isNetworkMetered);
Intent intent = new Intent(context, SyncthingService.class);
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
Intent intent = new Intent(DeviceStateHolder.ACTION_DEVICE_STATE_CHANGED);
intent.putExtra(DeviceStateHolder.EXTRA_IS_ALLOWED_NETWORK_CONNECTION, isAllowedConnection);
context.startService(intent);
lbm.sendBroadcast(intent);
// Make sure service is running.
context.startService(new Intent(context, SyncthingService.class));
}
}

View File

@ -0,0 +1,31 @@
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;
import com.nutomic.syncthingandroid.service.SyncthingService;
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);
}
}

View File

@ -1,31 +1,40 @@
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.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.google.common.base.Joiner;
import com.nutomic.syncthingandroid.receiver.BatteryReceiver;
import com.nutomic.syncthingandroid.receiver.NetworkReceiver;
import com.nutomic.syncthingandroid.receiver.PowerSaveModeChangedReceiver;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Holds information about the current wifi and charging state of the device.
*
* This information is actively read on construction, and then updated from intents that are passed
* to {@link #update(android.content.Intent)}.
* 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 {
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.
*/
@ -39,29 +48,53 @@ public class DeviceStateHolder {
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";
public interface OnDeviceStateChangedListener {
void onDeviceStateChanged();
}
private final Context mContext;
private final SharedPreferences mPreferences;
private final LocalBroadcastManager mBroadcastManager;
private final DeviceStateChangedReceiver mReceiver = new DeviceStateChangedReceiver();
private final OnDeviceStateChangedListener mListener;
private boolean mIsAllowedNetworkConnection = false;
private String mWifiSsid;
private boolean mIsCharging = false;
private boolean mIsPowerSaving = true;
public DeviceStateHolder(Context context) {
public DeviceStateHolder(Context context, OnDeviceStateChangedListener listener) {
mContext = context;
mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
mBroadcastManager = LocalBroadcastManager.getInstance(mContext);
mBroadcastManager.registerReceiver(mReceiver, new IntentFilter(ACTION_DEVICE_STATE_CHANGED));
mListener = listener;
BatteryReceiver.updateInitialChargingStatus(mContext);
NetworkReceiver.updateNetworkStatus(mContext);
PowerSaveModeChangedReceiver.updatePowerSavingState(mContext);
}
public void update(Intent intent) {
mIsAllowedNetworkConnection =
intent.getBooleanExtra(EXTRA_IS_ALLOWED_NETWORK_CONNECTION, mIsAllowedNetworkConnection);
mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging);
Log.i(TAG, "State updated, allowed network connection: " + mIsAllowedNetworkConnection +
", charging: " + mIsCharging);
public void shutdown() {
mBroadcastManager.unregisterReceiver(mReceiver);
}
updateWifiSsid();
private class DeviceStateChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
mIsAllowedNetworkConnection =
intent.getBooleanExtra(EXTRA_IS_ALLOWED_NETWORK_CONNECTION, mIsAllowedNetworkConnection);
mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging);
mIsPowerSaving = intent.getBooleanExtra(EXTRA_IS_POWER_SAVING, mIsPowerSaving);
Log.i(TAG, "State updated, allowed network connection: " + mIsAllowedNetworkConnection +
", charging: " + mIsCharging + ", power saving: " + mIsPowerSaving);
updateWifiSsid();
mListener.onDeviceStateChanged();
}
}
private void updateWifiSsid() {
@ -69,7 +102,7 @@ public class DeviceStateHolder {
WifiManager wifiManager =
(WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
// may be null, if WiFi has been turned off in meantime
// May be null, if WiFi has been turned off in meantime.
if (wifiInfo != null) {
mWifiSsid = wifiInfo.getSSID();
}
@ -78,24 +111,23 @@ public class DeviceStateHolder {
/**
* Determines if Syncthing should currently run.
*/
public boolean shouldRun() {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
mPreferences.getBoolean("respect_battery_saving", true) &&
pm.isPowerSaveMode()) {
boolean shouldRun() {
boolean prefRespectPowerSaving = mPreferences.getBoolean("respect_battery_saving", true);
if (prefRespectPowerSaving && mIsPowerSaving)
return false;
}
else if (SyncthingService.alwaysRunInBackground(mContext)) {
// Check wifi/charging state against preferences and start if ok.
if (SyncthingService.alwaysRunInBackground(mContext)) {
boolean prefStopMobileData = mPreferences.getBoolean(SyncthingService.PREF_SYNC_ONLY_WIFI, false);
boolean prefStopNotCharging = mPreferences.getBoolean(SyncthingService.PREF_SYNC_ONLY_CHARGING, false);
return (mIsCharging || !prefStopNotCharging) &&
(!prefStopMobileData || isWhitelistedNetworkConnection());
}
else {
return true;
if (prefStopMobileData && !isWhitelistedNetworkConnection())
return false;
if (prefStopNotCharging && !mIsCharging)
return false;
}
return true;
}
private boolean isWhitelistedNetworkConnection() {

View File

@ -28,6 +28,7 @@ import com.nutomic.syncthingandroid.activities.FirstStartActivity;
import com.nutomic.syncthingandroid.http.PollWebGuiAvailableTask;
import com.nutomic.syncthingandroid.model.Folder;
import com.nutomic.syncthingandroid.receiver.NetworkReceiver;
import com.nutomic.syncthingandroid.receiver.PowerSaveModeChangedReceiver;
import com.nutomic.syncthingandroid.util.ConfigXml;
import com.nutomic.syncthingandroid.util.FolderObserver;
@ -97,18 +98,6 @@ public class SyncthingService extends Service implements
private static final int NOTIFICATION_ACTIVE = 1;
private ConfigXml mConfig;
private RestApi mApi;
private EventProcessor mEventProcessor;
private final LinkedList<FolderObserver> mObservers = new LinkedList<>();
private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this);
private final NetworkReceiver mNetworkReceiver = new NetworkReceiver();
/**
* Callback for when the Syncthing web interface becomes first available after service start.
*/
@ -126,13 +115,6 @@ public class SyncthingService extends Service implements
private final HashSet<OnApiChangeListener> mOnApiChangeListeners =
new HashSet<>();
private final BroadcastReceiver mPowerSaveModeChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateState();
}
};
/**
* Indicates the current state of SyncthingService and of Syncthing itself.
*/
@ -151,6 +133,19 @@ public class SyncthingService extends Service implements
private State mCurrentState = State.INIT;
private ConfigXml mConfig;
private RestApi mApi;
private EventProcessor mEventProcessor;
private final LinkedList<FolderObserver> mObservers = new LinkedList<>();
private final SyncthingServiceBinder mBinder = new SyncthingServiceBinder(this);
private final NetworkReceiver mNetworkReceiver = new NetworkReceiver();
private final BroadcastReceiver mPowerSaveModeChangedReceiver = new PowerSaveModeChangedReceiver();
/**
* Object that can be locked upon when accessing mCurrentState
* Currently used to male onDestroy() and PollWebGuiAvailableTaskImpl.onPostExcecute() tread-safe
@ -184,9 +179,6 @@ public class SyncthingService extends Service implements
new SyncthingRunnable(this, SyncthingRunnable.Command.reset).run();
new StartupTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
});
} else {
mDeviceStateHolder.update(intent);
updateState();
}
return START_STICKY;
}
@ -285,7 +277,7 @@ public class SyncthingService extends Service implements
super.onCreate();
PRNGFixes.apply();
mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this);
mDeviceStateHolder = new DeviceStateHolder(SyncthingService.this, this::updateState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
registerReceiver(mPowerSaveModeChangedReceiver,
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
@ -393,6 +385,7 @@ public class SyncthingService extends Service implements
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
sp.unregisterOnSharedPreferenceChangeListener(this);
mDeviceStateHolder.shutdown();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
unregisterReceiver(mPowerSaveModeChangedReceiver);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)