mirror of https://github.com/BOINC/boinc.git
android: service sticky for GUI keep alive
This commit is contained in:
parent
6131a3c6bb
commit
985d91489b
|
@ -24,7 +24,7 @@
|
|||
<integer name="monitor_refresh_rate_ms">1000</integer>
|
||||
<integer name="monitor_setup_connection_retry_rate_ms">1000</integer>
|
||||
<integer name="monitor_setup_connection_retry_attempts">10</integer>
|
||||
<integer name="autostart_notification_id">460</integer>
|
||||
<integer name="autostart_notification_id">1</integer>
|
||||
<!-- Device status -->
|
||||
<integer name="minimum_device_status_refresh_rate_in_monitor_loops">10</integer>
|
||||
<!-- configuration on tab layout -->
|
||||
|
|
|
@ -115,6 +115,8 @@ public class BOINCActivity extends TabActivity {
|
|||
}
|
||||
|
||||
private void doBindService() {
|
||||
// start service to allow setForeground later on...
|
||||
startService(new Intent(this, Monitor.class));
|
||||
// Establish a connection with the service, onServiceConnected gets called when
|
||||
bindService(new Intent(this, Monitor.class), mConnection, Service.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
|
|
@ -171,8 +171,8 @@ public class PrefsActivity extends FragmentActivity {
|
|||
break;
|
||||
case R.string.prefs_show_notification_header: //app pref
|
||||
appPrefs.setShowNotification(isSet);
|
||||
ClientNotification.getInstance(getApplicationContext()).update(); // update notification
|
||||
populateLayout(); // updates status text
|
||||
ClientNotification.getInstance().update(getApplicationContext());
|
||||
break;
|
||||
case R.string.prefs_show_advanced_header: //app pref
|
||||
appPrefs.setShowAdvanced(isSet);
|
||||
|
|
|
@ -7,15 +7,20 @@ import android.app.NotificationManager;
|
|||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
public class ClientNotification {
|
||||
//private static final String TAG = "ClientNotification";
|
||||
private static final String TAG = "ClientNotification";
|
||||
|
||||
private static ClientNotification clientNotification = null;
|
||||
|
||||
public Notification notification;
|
||||
private Context context;
|
||||
private NotificationManager nm;
|
||||
private Integer notificationId;
|
||||
private PendingIntent contentIntent;
|
||||
|
||||
private boolean mIsEnabled = true;
|
||||
private int mOldComputingStatus = -1;
|
||||
private int mOldSuspendReason = -1;
|
||||
|
||||
|
@ -24,22 +29,30 @@ public class ClientNotification {
|
|||
* Constructs a new instance of the ClientNotification if not already constructed.
|
||||
* @return ClientNotification static instance
|
||||
*/
|
||||
public static synchronized ClientNotification getInstance() {
|
||||
if (clientNotification == null)
|
||||
clientNotification = new ClientNotification();
|
||||
|
||||
public static synchronized ClientNotification getInstance(Context ctx) {
|
||||
if (clientNotification == null) {
|
||||
clientNotification = new ClientNotification(ctx);
|
||||
}
|
||||
return clientNotification;
|
||||
}
|
||||
|
||||
public ClientNotification (Context ctx) {
|
||||
this.context = ctx;
|
||||
this.nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationId = context.getResources().getInteger(R.integer.autostart_notification_id);
|
||||
Intent intent = new Intent(context, BOINCActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
|
||||
contentIntent = PendingIntent.getActivity(context, 0, intent, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates notification with client's current status
|
||||
* @param context
|
||||
* @param updatedStatus new status
|
||||
*/
|
||||
public synchronized void update(Context context) {
|
||||
// check whether notification is allowed in preferences
|
||||
public synchronized void update() {
|
||||
// check whether notification is allowed in preferences
|
||||
if (!Monitor.getAppPrefs().getShowNotification()) {
|
||||
hide(context);
|
||||
Log.d(TAG,"cancelling notification");
|
||||
nm.cancel(notificationId);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,61 +62,55 @@ public class ClientNotification {
|
|||
// update notification
|
||||
if (clientNotification.mOldComputingStatus == -1
|
||||
|| updatedStatus.computingStatus.intValue() != clientNotification.mOldComputingStatus
|
||||
|| (updatedStatus.computingStatus == ClientStatus.COMPUTING_STATUS_SUSPENDED && updatedStatus.computingSuspendReason != clientNotification.mOldSuspendReason)) {
|
||||
if (clientNotification.mIsEnabled)
|
||||
updateNotification(context, updatedStatus.computingStatus);
|
||||
|| (updatedStatus.computingStatus == ClientStatus.COMPUTING_STATUS_SUSPENDED
|
||||
&& updatedStatus.computingSuspendReason != clientNotification.mOldSuspendReason)) {
|
||||
|
||||
nm.notify(notificationId, buildNotification());
|
||||
|
||||
// save status for comparison next time
|
||||
clientNotification.mOldComputingStatus = updatedStatus.computingStatus;
|
||||
clientNotification.mOldSuspendReason = updatedStatus.computingSuspendReason;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNotification(Context context, int status) {
|
||||
switch(status) {
|
||||
case ClientStatus.COMPUTING_STATUS_NEVER:
|
||||
show(context, R.drawable.ic_stat_notify_boinc_paused, BOINCActivity.class);
|
||||
break;
|
||||
case ClientStatus.COMPUTING_STATUS_SUSPENDED:
|
||||
show(context, R.drawable.ic_stat_notify_boinc_paused, BOINCActivity.class);
|
||||
break;
|
||||
case ClientStatus.COMPUTING_STATUS_IDLE:
|
||||
show(context, R.drawable.ic_stat_notify_boinc_paused, BOINCActivity.class);
|
||||
break;
|
||||
case ClientStatus.COMPUTING_STATUS_COMPUTING:
|
||||
show(context, R.drawable.ic_stat_notify_boinc_normal, BOINCActivity.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void show(Context context, int icon, Class<?> launchActivity) {
|
||||
private Notification buildNotification() {
|
||||
// get current client computingstatus
|
||||
Integer computingStatus = Monitor.getClientStatus().computingStatus;
|
||||
// get status string from ClientStatus
|
||||
String statusText = Monitor.getClientStatus().getCurrentStatusString();
|
||||
|
||||
// get notification ID
|
||||
Integer notificationId = context.getResources().getInteger(R.integer.autostart_notification_id);
|
||||
|
||||
// Set the icon, scrolling text and time-stamp
|
||||
notification = new Notification(
|
||||
icon,
|
||||
statusText,
|
||||
System.currentTimeMillis());
|
||||
// The PendingIntent to launch activity
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
|
||||
new Intent(context, launchActivity), 0);
|
||||
|
||||
// Set the info for the views that show in the notification panel.
|
||||
notification.setLatestEventInfo(context, context.getText(R.string.app_name),
|
||||
statusText, pendingIntent);
|
||||
notification.flags |= Notification.FLAG_NO_CLEAR;
|
||||
|
||||
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(notificationId, notification);
|
||||
// build notification
|
||||
Notification notification = new NotificationCompat.Builder(context)
|
||||
.setContentTitle(context.getString(R.string.app_name))
|
||||
.setContentText(statusText)
|
||||
.setSmallIcon(getIcon(computingStatus))
|
||||
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), getIcon(computingStatus)))
|
||||
.setContentIntent(contentIntent)
|
||||
.setOngoing(true)
|
||||
.build();
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
private void hide(Context context) {
|
||||
// get notification ID
|
||||
Integer notificationId = context.getResources().getInteger(R.integer.autostart_notification_id);
|
||||
|
||||
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.cancel(notificationId);
|
||||
// returns resource id of icon
|
||||
private int getIcon(int status) {
|
||||
int icon;
|
||||
switch(status) {
|
||||
case ClientStatus.COMPUTING_STATUS_NEVER:
|
||||
icon = R.drawable.ic_stat_notify_boinc_paused;
|
||||
break;
|
||||
case ClientStatus.COMPUTING_STATUS_SUSPENDED:
|
||||
icon = R.drawable.ic_stat_notify_boinc_paused;
|
||||
break;
|
||||
case ClientStatus.COMPUTING_STATUS_IDLE:
|
||||
icon = R.drawable.ic_stat_notify_boinc_paused;
|
||||
break;
|
||||
case ClientStatus.COMPUTING_STATUS_COMPUTING:
|
||||
icon = R.drawable.ic_stat_notify_boinc_normal;
|
||||
break;
|
||||
default:
|
||||
icon = R.drawable.ic_stat_notify_boinc_normal;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -503,7 +503,6 @@ public class Monitor extends Service {
|
|||
Log.d(TAG,"onDestroy()");
|
||||
|
||||
// Cancel the persistent notification.
|
||||
//
|
||||
((NotificationManager)getSystemService(Service.NOTIFICATION_SERVICE)).cancel(getResources().getInteger(R.integer.autostart_notification_id));
|
||||
|
||||
// Abort the ClientMonitorAsync thread
|
||||
|
@ -512,12 +511,6 @@ public class Monitor extends Service {
|
|||
monitorThread.interrupt();
|
||||
|
||||
clientStatus.setWakeLock(false); // release wakeLock, if held.
|
||||
|
||||
// Quit client here is not appropriate?!
|
||||
// Keep Client running until explecitely killed, independently from UI
|
||||
//quitClient();
|
||||
|
||||
//android.widget.Toast.makeText(this, "BOINC Monitor Service Stopped", android.widget.Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -525,28 +518,13 @@ public class Monitor extends Service {
|
|||
//this gets called after startService(intent) (either by BootReceiver or AndroidBOINCActivity, depending on the user's autostart configuration)
|
||||
Log.d(TAG, "onStartCommand()");
|
||||
/*
|
||||
* START_NOT_STICKY is now used and replaced START_STICKY in previous implementations.
|
||||
* Lifecycle events - e.g. killing apps by calling their "onDestroy" methods, or killing an app in the task manager - does not effect the non-Dalvik code like the native BOINC Client.
|
||||
* Therefore, it is not necessary for the service to get reactivated. When the user navigates back to the app (BOINC Manager), the service gets re-started from scratch.
|
||||
* Con: After user navigates back, it takes some time until current Client status is present.
|
||||
* Pro: Saves RAM/CPU.
|
||||
*
|
||||
* START_STICKY causes service to stay in memory until stopSelf() is called, even if all
|
||||
* Activities get destroyed by the system. Important for GUI keep-alive
|
||||
* For detailed service documentation see
|
||||
* http://android-developers.blogspot.com.au/2010/02/service-api-changes-starting-with.html
|
||||
*/
|
||||
return START_NOT_STICKY;
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
//sends broadcast about login (or register) result for login activity
|
||||
/*
|
||||
private void sendLoginResultBroadcast(Integer type, Integer result, String message) {
|
||||
Intent loginResults = new Intent();
|
||||
loginResults.setAction("edu.berkeley.boinc.loginresults");
|
||||
loginResults.putExtra("type", type);
|
||||
loginResults.putExtra("result", result);
|
||||
loginResults.putExtra("message", message);
|
||||
getApplicationContext().sendBroadcast(loginResults,null);
|
||||
}*/
|
||||
|
||||
public void restartMonitor() {
|
||||
if(Monitor.monitorActive) { //monitor is already active, launch cancelled
|
||||
|
@ -609,6 +587,9 @@ public class Monitor extends Service {
|
|||
|
||||
// set client status to SETUP_STATUS_CLOSED to adapt layout accordingly
|
||||
getClientStatus().setSetupStatus(ClientStatus.SETUP_STATUS_CLOSED,true);
|
||||
|
||||
//stop service, triggers onDestroy
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
public void setRunMode(Integer mode) {
|
||||
|
@ -964,7 +945,7 @@ public class Monitor extends Service {
|
|||
if( (status != null) && (state != null) && (state.results != null) && (state.projects != null) && (transfers != null)) {
|
||||
Monitor.getClientStatus().setClientStatus(status, state.results, state.projects, transfers);
|
||||
// Update status bar notification
|
||||
ClientNotification.getInstance().update(getApplicationContext());
|
||||
ClientNotification.getInstance(getApplicationContext()).update();
|
||||
} else {
|
||||
Log.d(TAG, "client status connection problem");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue