android: run service in foreground druing computation.

sets edu.berkeley.boinc.client.Monitor as foreground service while client is computing to prevent Android housekeeping to kill it under memory pressure.
consequently is notification preference only applicable to suspended state.
should not have an impact on device's cpu throttling, because only active during computation. As soon as computation suspends, service is put to background.
-GUI not active- client suspension can still occur when suspended for another reason.
This commit is contained in:
Joachim Fritzsch 2013-07-15 11:39:29 +02:00
parent 996e5e74cf
commit ba9f73930f
4 changed files with 54 additions and 22 deletions

View File

@ -159,7 +159,7 @@
<string name="prefs_network_daily_xfer_limit_mb_description">Limits the daily data traffic caused by BOINC.</string>
<string name="prefs_network_wifi_only_header">Transfer tasks on WiFi only</string>
<string name="prefs_autostart_header">Autostart</string>
<string name="prefs_show_notification_header">Show notifications</string>
<string name="prefs_show_notification_header">Show notification when suspended</string>
<string name="prefs_cpu_number_cpus_header">Used CPU cores</string>
<string name="prefs_cpu_number_cpus_description">Limits the number of CPU cores BOINC uses for computation.</string>
<string name="prefs_cpu_other_load_suspension_header">Pause at CPU usage above</string>

View File

@ -237,7 +237,7 @@ public class PrefsActivity extends FragmentActivity {
break;
case R.string.prefs_show_notification_header: //app pref
appPrefs.setShowNotification(isSet);
ClientNotification.getInstance(getApplicationContext()).update(); // update notification
ClientNotification.getInstance(getApplicationContext()).enable(isSet);
updateBoolPref(ID, isSet);
updateLayout();
break;

View File

@ -21,9 +21,12 @@ public class ClientNotification {
private NotificationManager nm;
private Integer notificationId;
private PendingIntent contentIntent;
private int mOldComputingStatus = -1;
private int mOldSuspendReason = -1;
// debug foreground state by running
// adb shell: dumpsys activity services edu.berkeley.boinc
private boolean foreground = false;
/**
* Returns a reference to a singleton ClientNotification object.
@ -49,30 +52,35 @@ public class ClientNotification {
/**
* Updates notification with client's current status
*/
public synchronized void update() {
// check whether notification is allowed in preferences
if (!Monitor.getAppPrefs().getShowNotification()) {
nm.cancel(notificationId);
clientNotification.mOldComputingStatus = -1;
return;
}
// try to get current client status from monitor
ClientStatus updatedStatus;
try{
updatedStatus = Monitor.getClientStatus();
} catch (Exception e){
if(Logging.WARNING) Log.w(Logging.TAG,"ClientNotification: Could not load data, clientStatus not initialized.");
return;
}
public synchronized void update(ClientStatus updatedStatus, Monitor monitorService) {
// update notification
// update notification, only after change in status
if (clientNotification.mOldComputingStatus == -1
|| updatedStatus.computingStatus.intValue() != clientNotification.mOldComputingStatus
|| (updatedStatus.computingStatus == ClientStatus.COMPUTING_STATUS_SUSPENDED
&& updatedStatus.computingSuspendReason != clientNotification.mOldSuspendReason)) {
nm.notify(notificationId, buildNotification(updatedStatus));
if(updatedStatus.computingStatus == ClientStatus.COMPUTING_STATUS_COMPUTING) {
// computing! set service as foreground
monitorService.startForeground(notificationId, buildNotification(updatedStatus));
if(Logging.DEBUG) Log.d(Logging.TAG,"ClientNotification.update() start service as foreground.");
foreground = true;
} else {
// not computing, set service as background
if(foreground) {
foreground = false;
monitorService.stopForeground(true);
if(Logging.DEBUG) Log.d(Logging.TAG,"ClientNotification.update() stop service as foreground.");
}
// check whether notification is allowed in preferences
if (!Monitor.getAppPrefs().getShowNotification()) {
enable(false);
return;
}
nm.notify(notificationId, buildNotification(updatedStatus));
}
// save status for comparison next time
clientNotification.mOldComputingStatus = updatedStatus.computingStatus;
@ -80,6 +88,30 @@ public class ClientNotification {
}
}
// called after change in notification preference
public synchronized void enable(Boolean enable) {
if(Logging.DEBUG) Log.d(Logging.TAG,"ClientNotification.enable() " + enable);
if(foreground) {
// foreground notification mandatory, do not change
if(Logging.DEBUG) Log.d(Logging.TAG,"ClientNotification.enable() service in foreground, do not change.");
} else {
// service in background, notification behavior configurable
if(enable){
try{
ClientStatus status = Monitor.getClientStatus();
nm.notify(notificationId, buildNotification(status));
// save status for comparison next time
clientNotification.mOldComputingStatus = status.computingStatus;
clientNotification.mOldSuspendReason = status.computingSuspendReason;
} catch (Exception e) {if(Logging.WARNING) Log.w(Logging.TAG,"ClientNotification.enable() failed!");}
} else {
nm.cancel(notificationId);
clientNotification.mOldComputingStatus = -1;
}
}
}
// cancels notification, called during client shutdown
public synchronized void cancel() {
nm.cancel(notificationId);

View File

@ -370,7 +370,7 @@ public class Monitor extends Service {
if( (status != null) && (state != null) && (state.results != null) && (state.projects != null) && (transfers != null) && (state.host_info != null)) {
Monitor.getClientStatus().setClientStatus(status, state.results, state.projects, transfers, state.host_info);
// Update status bar notification
ClientNotification.getInstance(getApplicationContext()).update();
ClientNotification.getInstance(getApplicationContext()).update(Monitor.getClientStatus(), this);
} else {
if(Logging.ERROR) Log.e(Logging.TAG, "readClientStatus(): connection problem");
}