package com.nutomic.syncthingandroid.syncthing; import android.annotation.TargetApi; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; 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.util.Log; import java.util.HashSet; import java.util.Set; /** * 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 * to {@link #update(android.content.Intent)}. */ public class DeviceStateHolder extends BroadcastReceiver { private static final String TAG = "DeviceStateHolder"; /** * Intent extra containing a boolean saying whether wifi is connected or not. */ public static final String EXTRA_HAS_WIFI = "com.nutomic.syncthingandroid.syncthing.DeviceStateHolder.HAS_WIFI"; /** * 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"; private final Context mContext; private boolean mIsWifiConnected = false; private String mWifiSsid; private boolean mIsCharging = false; @TargetApi(16) public DeviceStateHolder(Context context) { mContext = context; ConnectivityManager cm = (ConnectivityManager) 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(); } } /** * Receiver for {@link Intent#ACTION_BATTERY_CHANGED}, which is used to determine the initial * 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() { return mIsCharging; } public boolean isWifiConnected() { return mIsWifiConnected; } public void update(Intent intent) { mIsWifiConnected = intent.getBooleanExtra(EXTRA_HAS_WIFI, mIsWifiConnected); mIsCharging = intent.getBooleanExtra(EXTRA_IS_CHARGING, mIsCharging); if (mIsWifiConnected) { updateWifiSsid(); } else { mWifiSsid = null; } } public void updateWifiSsid() { mWifiSsid = null; WifiManager wifiManager = (WifiManager) mContext.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(); } } private String getWifiSsid() { return mWifiSsid; } /** * Determines if Syncthing should currently run. */ @TargetApi(21) public boolean shouldRun() { PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP && pm.isPowerSaveMode()) { return false; } else if (SyncthingService.alwaysRunInBackground(mContext)) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); // Check wifi/charging state against preferences and start if ok. boolean prefStopMobileData = prefs.getBoolean(SyncthingService.PREF_SYNC_ONLY_WIFI, false); boolean prefStopNotCharging = prefs.getBoolean(SyncthingService.PREF_SYNC_ONLY_CHARGING, false); return (isCharging() || !prefStopNotCharging) && (!prefStopMobileData || isAllowedWifiConnected()); } else { return true; } } private boolean isAllowedWifiConnected() { boolean wifiConnected = isWifiConnected(); if (wifiConnected) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); Set<String> ssids = sp.getStringSet(SyncthingService.PREF_SYNC_ONLY_WIFI_SSIDS, new HashSet<>()); if (ssids.isEmpty()) { Log.d(TAG, "All SSIDs allowed for syncing"); return true; } else { String ssid = getWifiSsid(); if (ssid != null) { if (ssids.contains(ssid)) { Log.d(TAG, "SSID [" + ssid + "] found in whitelist: " + ssids); return true; } Log.i(TAG, "SSID [" + ssid + "] not whitelisted: " + ssids); return false; } else { // Don't know the SSID (yet) (should not happen?!), so not allowing Log.w(TAG, "SSID unknown (yet), cannot check SSID whitelist. Disallowing sync."); return false; } } } Log.d(TAG, "Wifi not connected"); return false; } }