diff --git a/android/BOINC/res/values/configuration.xml b/android/BOINC/res/values/configuration.xml index e397daf06b..378f5b4fa7 100644 --- a/android/BOINC/res/values/configuration.xml +++ b/android/BOINC/res/values/configuration.xml @@ -25,6 +25,8 @@ 1000 10 460 + + 10 true true diff --git a/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java b/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java index 9e8a8b73b5..32c4fd41ff 100644 --- a/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java +++ b/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java @@ -46,6 +46,7 @@ import edu.berkeley.boinc.rpc.AccountIn; import edu.berkeley.boinc.rpc.AccountOut; import edu.berkeley.boinc.rpc.CcState; import edu.berkeley.boinc.rpc.CcStatus; +import edu.berkeley.boinc.rpc.DeviceStatus; import edu.berkeley.boinc.rpc.GlobalPreferences; import edu.berkeley.boinc.rpc.Message; import edu.berkeley.boinc.rpc.Project; @@ -919,6 +920,11 @@ public class Monitor extends Service { // Frequency of which the monitor updates client status via RPC, to often can cause reduced performance! private Integer refreshFrequency = getResources().getInteger(R.integer.monitor_refresh_rate_ms); + private Integer minimumDeviceStatusFrequency = getResources().getInteger(R.integer.minimum_device_status_refresh_rate_in_monitor_loops); + private Integer deviceStatusOmitCounter = 0; + + // DeviceStatus wrapper class + private DeviceStatus deviceStatus = new DeviceStatus(getApplicationContext()); @Override protected Boolean doInBackground(Integer... params) { @@ -933,6 +939,19 @@ public class Monitor extends Service { clientSetup(); sleep = false; } else { + // connection alive + + // set devices status + try { + if(deviceStatus.update() || deviceStatusOmitCounter >= minimumDeviceStatusFrequency) { + if(showRpcCommands) Log.d(TAG, "reportDeviceStatus"); + Boolean reportStatusSuccess = rpc.reportDeviceStatus(deviceStatus); + Log.d(TAG,"reportDeviceStatus returned: " + reportStatusSuccess); + if(reportStatusSuccess) deviceStatusOmitCounter = 0; + } else deviceStatusOmitCounter++; + } catch (Exception e) { Log.w(TAG, "device status update failed: " + e.getLocalizedMessage()); } + + // retrieve client status if(showRpcCommands) Log.d(TAG, "getCcStatus"); CcStatus status = rpc.getCcStatus(); diff --git a/android/BOINC/src/edu/berkeley/boinc/rpc/DeviceStatus.java b/android/BOINC/src/edu/berkeley/boinc/rpc/DeviceStatus.java new file mode 100644 index 0000000000..1a2ef39942 --- /dev/null +++ b/android/BOINC/src/edu/berkeley/boinc/rpc/DeviceStatus.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * This file is part of BOINC. + * http://boinc.berkeley.edu + * Copyright (C) 2012 University of California + * + * BOINC is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * BOINC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOINC. If not, see . + ******************************************************************************/ +package edu.berkeley.boinc.rpc; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.os.BatteryManager; +import android.util.Log; + +public class DeviceStatus{ + + private final String TAG = "Rpc.DeviceState"; + + // variables describing device status + private boolean on_ac_power; + private boolean on_usb_power; //not used + private int battery_charge_pct; + private int battery_state; //not used + private int battery_temperature_celcius; + private boolean wifi_online; + + // android specifics + private Context ctx;// context required for reading device status + private ConnectivityManager connManager; // connManager contains current wifi status + private Intent batteryStatus; // sticky intent, extras of Intent contain status, see BatteryManager. + + // constructor + public DeviceStatus(Context ctx) { + this.ctx = ctx; + this.connManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE); + batteryStatus = ctx.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + } + + // polls current device status + // returns true if data model has actually changed + // returns false if device status is unchanged -> avoid RPC call + public Boolean update() throws Exception { + if(ctx == null) { + Log.w(TAG,"context not set"); + return false; + } + + Boolean change = false; + + // check battery + batteryStatus = ctx.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + if(batteryStatus != null){ + + // calculate charging level + int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); + int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + int batteryPct = (int) ((level / (float) scale) * 100); // always rounds down + if(batteryPct <= 1 || batteryPct > 100) throw new Exception("battery level parsing error"); + if(batteryPct != battery_charge_pct) { + battery_charge_pct = batteryPct; + change = true; + } + + // temperature + int temperature = batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1) / 10; // always rounds down + if(temperature < 0) throw new Exception("temperature parsing error"); + if(temperature != battery_temperature_celcius) { + battery_temperature_celcius = temperature; + change = true; + } + + // plugged in + int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + if(status != BatteryManager.BATTERY_STATUS_DISCHARGING){ + // power supply online. not equivalent to BATTERY_STATUS_CHARGING which is not the case when full and plugged in + if(!on_ac_power) change = true; // if different from before, set flag + on_ac_power = true; + } else { + //power supply offline + if(on_ac_power) change = true; // if different from before, set flag + on_ac_power = false; + } + } + + // check wifi status + if(connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()){ + //wifi is online + if(!wifi_online) change = true; // if different from before, set flag + wifi_online = true; + } else { + //wifi offline + if(wifi_online) change = true; // if different from before, set flag + wifi_online = false; + } + + Log.d(TAG, "change: " + change + " - power supply: " + on_ac_power + " ; level: " + battery_charge_pct + " ; temperature: " + battery_temperature_celcius + " ; wifi: " + wifi_online); + return change; + } + + // getter + public boolean isOn_ac_power() { + return on_ac_power; + } + + public boolean isOn_usb_power() { + return on_usb_power; + } + + public int getBattery_charge_pct() { + return battery_charge_pct; + } + + public int getBattery_state() { + return battery_state; + } + + public int getBattery_temperature_celcius() { + return battery_temperature_celcius; + } + + public boolean isWifi_online() { + return wifi_online; + } +} diff --git a/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java b/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java index 79cc3a210d..1b22ea0db0 100644 --- a/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java +++ b/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java @@ -580,6 +580,41 @@ public class RpcClient { } } + /** + * Reports the current device state to the BOINC core client, + * if not called frequently, BOINC core client will suspend + * @return true for success, false for failure + */ + public synchronized boolean reportDeviceStatus(DeviceStatus deviceStatus) { + mLastErrorMessage = null; + mRequest.setLength(0); + mRequest.append("\n \n "); + mRequest.append(deviceStatus.isOn_ac_power() ? 1 : 0); + mRequest.append("\n "); + mRequest.append(deviceStatus.isOn_usb_power() ? 1 : 0); + mRequest.append("\n "); + mRequest.append(deviceStatus.getBattery_charge_pct()); + mRequest.append("\n "); + mRequest.append(deviceStatus.getBattery_state()); + mRequest.append("\n "); + mRequest.append(deviceStatus.getBattery_temperature_celcius()); + mRequest.append("\n "); + mRequest.append(deviceStatus.isWifi_online() ? 1 : 0); + mRequest.append("\n \n\n"); + try { + sendRequest(mRequest.toString()); + SimpleReplyParser parser = SimpleReplyParser.parse(receiveReply()); + if (parser == null) + return false; + mLastErrorMessage = parser.getErrorMessage(); + return parser.result(); + } + catch (IOException e) { + if (Logging.WARNING) Log.w(TAG, "error in networkAvailable()", e); + return false; + } + } + /** * Tells the BOINC core client that a network connection is available, * and that it should do as much network activity as it can. diff --git a/android/BOINC/src/edu/berkeley/boinc/utils/BOINCDefs.java b/android/BOINC/src/edu/berkeley/boinc/utils/BOINCDefs.java index 1db00de0b7..3761d4331f 100644 --- a/android/BOINC/src/edu/berkeley/boinc/utils/BOINCDefs.java +++ b/android/BOINC/src/edu/berkeley/boinc/utils/BOINCDefs.java @@ -105,6 +105,7 @@ public class BOINCDefs { public static final int SUSPEND_REASON_WIFI_STATE = 4097; public static final int SUSPEND_REASON_BATTERY_CHARGING = 4098; public static final int SUSPEND_REASON_BATTERY_OVERHEATED = 4099; + public static final int SUSPEND_REASON_NO_GUI_KEEPALIVE = 4100; // Values of RESULT::state // THESE MUST BE IN NUMERICAL ORDER