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