diff --git a/android/BOINC/res/drawable-hdpi/ic_menu_add.png b/android/BOINC/res/drawable-hdpi/ic_menu_add.png
new file mode 100644
index 0000000000..444e8a5ee8
Binary files /dev/null and b/android/BOINC/res/drawable-hdpi/ic_menu_add.png differ
diff --git a/android/BOINC/res/drawable-ldpi/ic_menu_add.png b/android/BOINC/res/drawable-ldpi/ic_menu_add.png
new file mode 100644
index 0000000000..89620af8c0
Binary files /dev/null and b/android/BOINC/res/drawable-ldpi/ic_menu_add.png differ
diff --git a/android/BOINC/res/drawable-mdpi/ic_menu_add.png b/android/BOINC/res/drawable-mdpi/ic_menu_add.png
new file mode 100644
index 0000000000..361c7c460e
Binary files /dev/null and b/android/BOINC/res/drawable-mdpi/ic_menu_add.png differ
diff --git a/android/BOINC/res/drawable-xhdpi/ic_menu_add.png b/android/BOINC/res/drawable-xhdpi/ic_menu_add.png
new file mode 100644
index 0000000000..7d498a96e2
Binary files /dev/null and b/android/BOINC/res/drawable-xhdpi/ic_menu_add.png differ
diff --git a/android/BOINC/res/drawable/abortw24.png b/android/BOINC/res/drawable/abortw24.png
new file mode 100644
index 0000000000..7dffc3f616
Binary files /dev/null and b/android/BOINC/res/drawable/abortw24.png differ
diff --git a/android/BOINC/res/drawable/pausew24.png b/android/BOINC/res/drawable/pausew24.png
new file mode 100644
index 0000000000..bbc8b81a13
Binary files /dev/null and b/android/BOINC/res/drawable/pausew24.png differ
diff --git a/android/BOINC/res/layout/prefs_layout_loading.xml b/android/BOINC/res/layout/prefs_layout_loading.xml
new file mode 100644
index 0000000000..92a5effad9
--- /dev/null
+++ b/android/BOINC/res/layout/prefs_layout_loading.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
diff --git a/android/BOINC/res/layout/tasks_layout_listitem.xml b/android/BOINC/res/layout/tasks_layout_listitem.xml
index a75a61567d..471714baa6 100644
--- a/android/BOINC/res/layout/tasks_layout_listitem.xml
+++ b/android/BOINC/res/layout/tasks_layout_listitem.xml
@@ -73,6 +73,8 @@
-
+
diff --git a/android/BOINC/res/layout/tasks_layout_listitem_expansion.xml b/android/BOINC/res/layout/tasks_layout_listitem_expansion.xml
new file mode 100644
index 0000000000..876fc3b593
--- /dev/null
+++ b/android/BOINC/res/layout/tasks_layout_listitem_expansion.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/BOINC/res/values/strings.xml b/android/BOINC/res/values/strings.xml
index 4b605a7b7c..d30ebbefaa 100644
--- a/android/BOINC/res/values/strings.xml
+++ b/android/BOINC/res/values/strings.xml
@@ -197,6 +197,12 @@
paused
stopping
stopping
+
+
+ Abort task
+ Abort task:
+ Abort
+ Cancel
Reading transfers…
diff --git a/android/BOINC/src/edu/berkeley/boinc/AppPreferences.java b/android/BOINC/src/edu/berkeley/boinc/AppPreferences.java
index ce72bae2df..daad27aa04 100644
--- a/android/BOINC/src/edu/berkeley/boinc/AppPreferences.java
+++ b/android/BOINC/src/edu/berkeley/boinc/AppPreferences.java
@@ -18,7 +18,6 @@
******************************************************************************/
package edu.berkeley.boinc;
-import edu.berkeley.boinc.client.ClientNotification;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
diff --git a/android/BOINC/src/edu/berkeley/boinc/ConfirmationDialog.java b/android/BOINC/src/edu/berkeley/boinc/ConfirmationDialog.java
new file mode 100644
index 0000000000..e0eb9f2b5d
--- /dev/null
+++ b/android/BOINC/src/edu/berkeley/boinc/ConfirmationDialog.java
@@ -0,0 +1,50 @@
+package edu.berkeley.boinc;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.content.DialogInterface.OnClickListener;
+
+public class ConfirmationDialog extends android.support.v4.app.DialogFragment {
+ private OnClickListener mConfirmClickListener = null;
+
+ public static ConfirmationDialog newInstance(String title, String message, String confirm) {
+ ConfirmationDialog frag = new ConfirmationDialog();
+ Bundle args = new Bundle();
+ args.putString("title", title);
+ args.putString("message", message);
+ args.putString("confirm", confirm);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ String title = getArguments().getString("title");
+ String message = getArguments().getString("message");
+ String confirm = getArguments().getString("confirm");
+
+ return new AlertDialog.Builder(getActivity())
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(title)
+ .setMessage(message)
+ .setPositiveButton(confirm, mConfirmClickListener)
+ .setNegativeButton("Cancel", new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dismiss();
+ }
+ })
+ .create();
+ }
+
+ public void setConfirmationClicklistener(OnClickListener cl) {
+ mConfirmClickListener = cl;
+ }
+
+ public interface ConfirmationDialogListener {
+ void onDialogRead();
+ void onDialogChecked(boolean isChecked);
+ }
+}
diff --git a/android/BOINC/src/edu/berkeley/boinc/TasksActivity.java b/android/BOINC/src/edu/berkeley/boinc/TasksActivity.java
index 00a33866c3..4c73d330c4 100644
--- a/android/BOINC/src/edu/berkeley/boinc/TasksActivity.java
+++ b/android/BOINC/src/edu/berkeley/boinc/TasksActivity.java
@@ -21,30 +21,54 @@ package edu.berkeley.boinc;
import java.util.ArrayList;
import edu.berkeley.boinc.adapter.TasksListAdapter;
+import edu.berkeley.boinc.client.ClientStatus;
import edu.berkeley.boinc.client.Monitor;
import edu.berkeley.boinc.rpc.Result;
-import android.app.Activity;
+import edu.berkeley.boinc.utils.BOINCDefs;
+import android.app.Service;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.app.FragmentActivity;
import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
import android.widget.ListView;
-import android.widget.TextView;
-public class TasksActivity extends Activity {
+public class TasksActivity extends FragmentActivity {
private final String TAG = "BOINC TasksActivity";
+
+ private Monitor monitor;
+ private Boolean mIsBound;
+
+ private ClientStatus status; //client status, new information gets parsed by monitor, changes notified by "clientstatus" broadcast. read Result from here, to get information about tasks.
private ListView lv;
private TasksListAdapter listAdapter;
- private ArrayList data = new ArrayList(); //Adapter for list data
-
- // Controls whether initialization of view elements of "tasks_layout"
- // is required. This is the case, every time the layout switched.
- private Boolean initialSetupRequired = true;
+ private ArrayList data = new ArrayList(); //Adapter for list data
+ private Boolean setup = false;
+
+ // This is called when the connection with the service has been established,
+ // getService returns the Monitor object that is needed to call functions.
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ monitor = ((Monitor.LocalBinder)service).getService();
+ mIsBound = true;
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ monitor = null;
+ mIsBound = false;
+ }
+ };
private BroadcastReceiver mClientStatusChangeRec = new BroadcastReceiver() {
@@ -52,15 +76,26 @@ public class TasksActivity extends Activity {
@Override
public void onReceive(Context context,Intent intent) {
Log.d(TAG,"onReceive");
- populateLayout();
+ loadData();
}
};
private IntentFilter ifcsc = new IntentFilter("edu.berkeley.boinc.clientstatuschange");
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- Log.d(TAG,"onCreate");
+
+ setContentView(R.layout.tasks_layout);
+ // Establish a connection with the service, onServiceConnected gets called when
+ // (calling within Tab needs getApplicationContext() for bindService to work!)
+ getApplicationContext().bindService(new Intent(this, Monitor.class), mConnection, Service.START_STICKY_COMPATIBILITY);
+
+ //get singleton client status from monitor
+ status = Monitor.getClientStatus();
+
+ //load data model
+ loadData();
+
+ Log.d(TAG, "onCreate");
}
public void onResume() {
@@ -68,7 +103,7 @@ public class TasksActivity extends Activity {
//register noisy clientStatusChangeReceiver here, so only active when Activity is visible
Log.d(TAG+"-onResume","register receiver");
registerReceiver(mClientStatusChangeRec,ifcsc);
- populateLayout();
+ loadData();
}
public void onPause() {
@@ -78,44 +113,167 @@ public class TasksActivity extends Activity {
super.onPause();
}
+ @Override
+ protected void onDestroy() {
+ Log.d(TAG, "onDestroy()");
+
+ if (mIsBound) {
+ getApplicationContext().unbindService(mConnection);
+ mIsBound = false;
+ }
+
+ super.onDestroy();
+ }
- private void populateLayout() {
- try {
- //setup list and adapter
- ArrayList tmpA = Monitor.getClientStatus().getTasks();
-
- if(tmpA == null) {
- setLayoutLoading();
- return;
- }
-
+ private void loadData() {
+ //setup list and adapter
+ ArrayList tmpA = status.getTasks();
+ if(tmpA!=null) { //can be null before first monitor status cycle (e.g. when not logged in or during startup)
+
//deep copy, so ArrayList adapter actually recognizes the difference
- data.clear();
- for (Result tmp: tmpA) {
- data.add(tmp);
- }
-
- if(initialSetupRequired) {// first time we got proper results, setup adapter
- initialSetupRequired = false;
- setContentView(R.layout.tasks_layout);
+ updateData(tmpA);
+
+ if(!setup) { //first time we got proper results, setup adapter
lv = (ListView) findViewById(R.id.tasksList);
- listAdapter = new TasksListAdapter(TasksActivity.this,R.id.tasksList,data);
- lv.setAdapter(listAdapter);
- }
+ listAdapter = new TasksListAdapter(TasksActivity.this,R.id.tasksList,data);
+ lv.setAdapter(listAdapter);
+
+ setup = true;
+ }
Log.d(TAG,"loadData: array contains " + data.size() + " results.");
listAdapter.notifyDataSetChanged(); //force list adapter to refresh
-
- } catch (Exception e) {
- // data retrieval failed, set layout to loading...
- setLayoutLoading();
+
+ } else {
+ Log.d(TAG, "loadData array is null");
}
}
-
- private void setLayoutLoading() {
- setContentView(R.layout.generic_layout_loading);
- TextView loadingHeader = (TextView)findViewById(R.id.loading_header);
- loadingHeader.setText(R.string.tasks_loading);
- initialSetupRequired = true;
+
+ private void updateData(ArrayList newData) {
+ // Create a new task data list based on new data
+ ArrayList tdl = new ArrayList();
+ for (Result r : newData) {
+ tdl.add(new TaskData(r));
+ }
+ // search for the same id in the old tasks
+ // maybe tasks were rearranged or updated
+ for (int i = 0; i < tdl.size(); i++) {
+ int j;
+ for (j = 0; j < data.size(); j++) {
+ if (tdl.get(i).id.equals(data.get(j).id)) {
+ // this task is old.
+ // retrieve expansion state
+ tdl.get(i).expanded = data.get(j).expanded;
+ break;
+ }
+ }
+ if (j == data.size()) {
+ // this is a new task, so add it
+ data.add(tdl.get(i));
+ }
+ }
+ // save new task data list
+ data.clear();
+
+ for (TaskData td: tdl) {
+ data.add(td);
+ }
+ }
+
+ public class TaskData {
+ public static final int TASK_STATE_UNKNOWN = 0;
+ public static final int TASK_STATE_PAUSED = 1;
+ public static final int TASK_STATE_RUNNING = 2;
+
+ public static final int TASK_STATE_ACTIVE = 10;
+ public static final int TASK_STATE_ABORTED = 11;
+
+ public Result result = null;
+ public boolean expanded = false;
+ public String id = "";
+ public int nextRunState = TASK_STATE_UNKNOWN;
+ public int currentRunState = TASK_STATE_UNKNOWN;
+ public int nextAbortState = TASK_STATE_UNKNOWN;
+ public int currentAbortState = TASK_STATE_UNKNOWN;
+
+ public TaskData(Result data) {
+ this.result = data;
+ this.expanded = false;
+ this.id = data.name;
+ this.currentRunState = determineRunningState();
+ this.nextRunState = this.currentRunState;
+ this.currentAbortState = determineAbortState();
+ this.nextAbortState = this.currentAbortState;
+ }
+
+ public final OnClickListener taskClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ expanded = !expanded;
+ listAdapter.notifyDataSetChanged(); //force list adapter to refresh
+ }
+ };
+
+ public final OnClickListener abortClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ ConfirmationDialog cd = ConfirmationDialog.newInstance(
+ getString(R.string.confirm_abort_task_title) + "?",
+ getString(R.string.confirm_abort_task_message) + " " + result.name,
+ getString(R.string.confirm_abort_task_confirm));
+ cd.setConfirmationClicklistener(new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ nextAbortState = TASK_STATE_ABORTED;
+ monitor.abortResultAsync(result.project_url, result.name);
+ }
+ });
+ cd.show(getSupportFragmentManager(), "");
+ listAdapter.notifyDataSetChanged(); //force list adapter to refresh
+ }
+ };
+
+ public final OnClickListener suspendClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ nextRunState = TASK_STATE_PAUSED;
+ monitor.suspendResultAsync(result.project_url, result.name);
+ listAdapter.notifyDataSetChanged(); //force list adapter to refresh
+ }
+ };
+
+ public final OnClickListener resumeClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ nextRunState = TASK_STATE_RUNNING;
+ monitor.resumeResultAsync(result.project_url, result.name);
+ listAdapter.notifyDataSetChanged(); //force list adapter to refresh
+ }
+ };
+
+ public int determineRunningState() {
+ if(result.active_task) {
+ if(result.active_task_state == BOINCDefs.PROCESS_EXECUTING) {
+ //running
+ return TASK_STATE_RUNNING;
+ } else {
+ //suspended - ready to run
+ return TASK_STATE_PAUSED;
+ }
+ } else {
+ //paused or stopped
+ return TASK_STATE_PAUSED;
+ }
+ }
+
+ public int determineAbortState() {
+ if(!result.active_task) {
+ switch (result.state) {
+ case 6:
+ return TASK_STATE_ABORTED;
+ }
+ }
+ return TASK_STATE_ACTIVE;
+ }
}
}
diff --git a/android/BOINC/src/edu/berkeley/boinc/adapter/TasksListAdapter.java b/android/BOINC/src/edu/berkeley/boinc/adapter/TasksListAdapter.java
index 1f5e4f9ba3..3213f1fa90 100644
--- a/android/BOINC/src/edu/berkeley/boinc/adapter/TasksListAdapter.java
+++ b/android/BOINC/src/edu/berkeley/boinc/adapter/TasksListAdapter.java
@@ -18,56 +18,63 @@
******************************************************************************/
package edu.berkeley.boinc.adapter;
+import java.sql.Date;
import java.util.ArrayList;
import edu.berkeley.boinc.R;
-import edu.berkeley.boinc.rpc.Result;
+import edu.berkeley.boinc.TasksActivity.TaskData;
import edu.berkeley.boinc.utils.BOINCDefs;
import android.app.Activity;
import android.content.Context;
+import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
import android.widget.TextView;
-public class TasksListAdapter extends ArrayAdapter{
+public class TasksListAdapter extends ArrayAdapter{
//private final String TAG = "TasksListAdapter";
- private ArrayList entries;
- private Activity activity;
+ private ArrayList entries;
+ private Activity activity;
- public TasksListAdapter(Activity a, int textViewResourceId, ArrayList entries) {
- super(a, textViewResourceId, entries);
- this.entries = entries;
- this.activity = a;
- }
+ public TasksListAdapter(Activity a, int textViewResourceId, ArrayList entries) {
+ super(a, textViewResourceId, entries);
+ this.entries = entries;
+ this.activity = a;
+ }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
- LayoutInflater vi = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(R.layout.tasks_layout_listitem, null);
+ View v = convertView;
+ LayoutInflater vi = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ v = vi.inflate(R.layout.tasks_layout_listitem, null);
+ v.setOnClickListener(entries.get(position).taskClickListener);
+
ProgressBar pb = (ProgressBar) v.findViewById(R.id.progressBar);
TextView header = (TextView) v.findViewById(R.id.taskName);
TextView status = (TextView) v.findViewById(R.id.taskStatus);
TextView time = (TextView) v.findViewById(R.id.taskTime);
TextView progress = (TextView) v.findViewById(R.id.taskProgress);
- Result listItem = entries.get(position);
-
+ TaskData listItem = entries.get(position);
+
pb.setIndeterminate(false);
- pb.setProgressDrawable(this.activity.getResources().getDrawable((determineProgressBarLayout(listItem))));
+ pb.setProgressDrawable(this.activity.getResources().getDrawable((determineProgressBarLayout(listItem))));
//v.setTag(listItem.name);
- String headerT = "Name: " + listItem.name;
+ String headerT = "Name: " + listItem.result.name;
header.setText(headerT);
- Float fraction = listItem.fraction_done;
- if(!listItem.active_task && listItem.ready_to_report) { //fraction not available, set it to 100
+ Float fraction = listItem.result.fraction_done;
+ if(!listItem.result.active_task && listItem.result.ready_to_report) { //fraction not available, set it to 100
fraction = Float.valueOf((float) 1.0);
}
pb.setProgress(Math.round(fraction * pb.getMax()));
@@ -77,83 +84,142 @@ public class TasksListAdapter extends ArrayAdapter{
String statusT = determineStatusText(listItem);
status.setText(statusT);
- int elapsedTime = (int)listItem.elapsed_time;
+ int elapsedTime = (int)listItem.result.elapsed_time;
time.setText(String.format("%02d:%02d:%02d", elapsedTime/3600, (elapsedTime/60)%60, elapsedTime%60));
-
- return v;
- }
+
+ RelativeLayout ll = (RelativeLayout) v.findViewById(R.id.expansion);
+ if (listItem.expanded) {
+ ll.setVisibility(View.VISIBLE);
+ // update resume/suspend state (button state)
+ listItem.currentRunState = listItem.determineRunningState();
+ // update abort state (button state)
+ listItem.currentAbortState = listItem.determineAbortState();
+ // set deadline
+ String deadline = (String) DateFormat.format("E d MMM yyyy hh:mm:ss aa", new Date(listItem.result.report_deadline*1000));
+ ((TextView) v.findViewById(R.id.deadline)).setText("Deadline: " + deadline);
+ // set project name
+ ((TextView) v.findViewById(R.id.projectName)).setText("Project name: " + listItem.result.project_url);
+ // TODO: set application friendly name
+
+ ImageView suspendResume = (ImageView) v.findViewById(R.id.suspendResumeTask);
+ if (listItem.currentRunState == listItem.nextRunState) {
+ // current button state is same as expected
+ suspendResume.setEnabled(true);
+ suspendResume.setClickable(true);
+ if (listItem.currentRunState == TaskData.TASK_STATE_RUNNING) {
+ suspendResume.setOnClickListener(listItem.suspendClickListener);
+ suspendResume.setImageResource(R.drawable.pausew24);
+ } else {
+ suspendResume.setOnClickListener(listItem.resumeClickListener);
+ suspendResume.setImageResource(R.drawable.playw24);
+ }
+ } else {
+ // waiting for transient state to be as expected
+ // button needs to be disabled (no action should be taken while waiting)
+ suspendResume.setEnabled(false);
+ suspendResume.setClickable(false);
+ suspendResume.setOnClickListener(null);
+ if (listItem.currentRunState == TaskData.TASK_STATE_RUNNING) {
+ suspendResume.setImageResource(R.drawable.pausew24);
+ } else {
+ suspendResume.setImageResource(R.drawable.playw24);
+ }
+ }
+ if (listItem.currentAbortState == listItem.nextAbortState) {
+ // current button state is same as expected
+ if (listItem.currentAbortState == TaskData.TASK_STATE_ABORTED) {
+ suspendResume.setEnabled(false);
+ suspendResume.setClickable(false);
+ } else {
+ suspendResume.setEnabled(true);
+ suspendResume.setClickable(true);
+ ((ImageView) v.findViewById(R.id.abortTask)).setOnClickListener(listItem.abortClickListener);
+ }
+ } else {
+ // waiting for transient state to be as expected
+ // button needs to be disabled (no action should be taken while waiting)
+ suspendResume.setEnabled(false);
+ suspendResume.setClickable(false);
+ suspendResume.setOnClickListener(null);
+ }
+ } else {
+ ll.setVisibility(View.GONE);
+ }
+
+ return v;
+ }
+
+ private String determineStatusText(TaskData tmp) {
+ String text = "";
+ if(tmp.result.active_task) {
+ switch (tmp.result.active_task_state) {
+ case 0:
+ text = activity.getString(R.string.tasks_active_uninitialized);
+ break;
+ case 1:
+ text = activity.getString(R.string.tasks_active_executing);
+ break;
+ case 5:
+ text = activity.getString(R.string.tasks_active_abort_pending);
+ break;
+ case 8:
+ text = activity.getString(R.string.tasks_active_quit_pending);
+ break;
+ case 9:
+ text = activity.getString(R.string.tasks_active_suspended);
+ break;
+ }
+ } else {
+ switch (tmp.result.state) {
+ case 0:
+ text = activity.getString(R.string.tasks_result_new);
+ break;
+ case 1:
+ text = activity.getString(R.string.tasks_result_files_downloading);
+ break;
+ case 2:
+ text = activity.getString(R.string.tasks_result_files_downloaded);
+ break;
+ case 3:
+ text = activity.getString(R.string.tasks_result_compute_error);
+ break;
+ case 4:
+ text = activity.getString(R.string.tasks_result_files_uploading);
+ break;
+ case 5:
+ text = activity.getString(R.string.tasks_result_files_uploaded);
+ break;
+ case 6:
+ text = activity.getString(R.string.tasks_result_aborted);
+ break;
+ case 7:
+ text = activity.getString(R.string.tasks_result_upload_failed);
+ break;
+ }
+ }
+ return text;
+ }
- private String determineStatusText(Result tmp) {
- String text = "";
- if(tmp.active_task) {
- switch (tmp.active_task_state) {
- case 0:
- text = activity.getString(R.string.tasks_active_uninitialized);
- break;
- case 1:
- text = activity.getString(R.string.tasks_active_executing);
- break;
- case 5:
- text = activity.getString(R.string.tasks_active_abort_pending);
- break;
- case 8:
- text = activity.getString(R.string.tasks_active_quit_pending);
- break;
- case 9:
- text = activity.getString(R.string.tasks_active_suspended);
- break;
- }
- } else {
- switch (tmp.state) {
- case 0:
- text = activity.getString(R.string.tasks_result_new);
- break;
- case 1:
- text = activity.getString(R.string.tasks_result_files_downloading);
- break;
- case 2:
- text = activity.getString(R.string.tasks_result_files_downloaded);
- break;
- case 3:
- text = activity.getString(R.string.tasks_result_compute_error);
- break;
- case 4:
- text = activity.getString(R.string.tasks_result_files_uploading);
- break;
- case 5:
- text = activity.getString(R.string.tasks_result_files_uploaded);
- break;
- case 6:
- text = activity.getString(R.string.tasks_result_aborted);
- break;
- case 7:
- text = activity.getString(R.string.tasks_result_upload_failed);
- break;
- }
- }
- return text;
- }
-
- private Integer determineProgressBarLayout(Result tmp) {
- if(tmp.active_task) {
- if(tmp.active_task_state == BOINCDefs.PROCESS_EXECUTING) {
- //running
- return R.drawable.progressbar_active;
- } else {
- //suspended - ready to run
- return R.drawable.progressbar_paused;
- }
- } else {
- if((tmp.state == BOINCDefs.RESULT_ABORTED) || (tmp.state == BOINCDefs.RESULT_UPLOAD_FAILED) || (tmp.state == BOINCDefs.RESULT_COMPUTE_ERROR)) {
- //error
- return R.drawable.progressbar_error;
- } else if (tmp.ready_to_report) {
- //finished
- return R.drawable.progressbar_active;
- } else {
- //paused or stopped
- return R.drawable.progressbar_paused;
- }
- }
- }
+ private Integer determineProgressBarLayout(TaskData tmp) {
+ if(tmp.result.active_task) {
+ if(tmp.result.active_task_state == BOINCDefs.PROCESS_EXECUTING) {
+ //running
+ return R.drawable.progressbar_active;
+ } else {
+ //suspended - ready to run
+ return R.drawable.progressbar_paused;
+ }
+ } else {
+ if((tmp.result.state == BOINCDefs.RESULT_ABORTED) || (tmp.result.state == BOINCDefs.RESULT_UPLOAD_FAILED) || (tmp.result.state == BOINCDefs.RESULT_COMPUTE_ERROR)) {
+ //error
+ return R.drawable.progressbar_error;
+ } else if (tmp.result.ready_to_report) {
+ //finished
+ return R.drawable.progressbar_active;
+ } else {
+ //paused or stopped
+ return R.drawable.progressbar_paused;
+ }
+ }
+ }
}
diff --git a/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java b/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java
index 6726f35f8e..fed3ed954a 100644
--- a/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java
+++ b/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java
@@ -810,6 +810,42 @@ public class Monitor extends Service {
param[1] = name;
(new TransferRetryAsync()).execute(param);
}
+
+ public Boolean suspendResult(String url, String name){
+ return rpc.resultOp(RpcClient.RESULT_SUSPEND, url, name);
+ }
+
+ public void suspendResultAsync(String url, String name){
+ Log.d(TAG, "suspendResultAsync");
+ String[] param = new String[2];
+ param[0] = url;
+ param[1] = name;
+ (new SuspendResultAsync()).execute(param);
+ }
+
+ public Boolean resumeResult(String url, String name){
+ return rpc.resultOp(RpcClient.RESULT_RESUME, url, name);
+ }
+
+ public void resumeResultAsync(String url, String name){
+ Log.d(TAG, "resumeResultAsync");
+ String[] param = new String[2];
+ param[0] = url;
+ param[1] = name;
+ (new ResumeResultAsync()).execute(param);
+ }
+
+ public Boolean abortResult(String url, String name){
+ return rpc.resultOp(RpcClient.RESULT_RESUME, url, name);
+ }
+
+ public void abortResultAsync(String url, String name){
+ Log.d(TAG, "abortResultAsync");
+ String[] param = new String[2];
+ param[0] = url;
+ param[1] = name;
+ (new AbortResultAsync()).execute(param);
+ }
public AccountOut createAccount(String url, String email, String userName, String pwd, String teamName) {
AccountIn information = new AccountIn();
@@ -1067,6 +1103,98 @@ public class Monitor extends Service {
}
}
+ private final class SuspendResultAsync extends AsyncTask {
+
+ private final String TAG = "SuspendResultAsync";
+
+ private String url;
+ private String name;
+
+ @Override
+ protected Boolean doInBackground(String... params) {
+ this.url = params[0];
+ this.name = params[1];
+ publishProgress("doInBackground() - SuspendResultAsync url: " + url + " Name: " + name);
+
+ Boolean retry = rpc.resultOp(RpcClient.RESULT_SUSPEND, url, name);
+ if(retry) {
+ publishProgress("successful.");
+ }
+ return retry;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean success) {
+ forceRefresh();
+ }
+
+ @Override
+ protected void onProgressUpdate(String... arg0) {
+ Log.d(TAG, "onProgressUpdate - " + arg0[0]);
+ }
+ }
+
+ private final class ResumeResultAsync extends AsyncTask {
+
+ private final String TAG = "ResumeResultAsync";
+
+ private String url;
+ private String name;
+
+ @Override
+ protected Boolean doInBackground(String... params) {
+ this.url = params[0];
+ this.name = params[1];
+ publishProgress("doInBackground() - ResumeResultAsync url: " + url + " Name: " + name);
+ Boolean retry = rpc.resultOp(RpcClient.RESULT_RESUME, url, name);
+ if(retry) {
+ publishProgress("successful.");
+ }
+ return retry;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean success) {
+ forceRefresh();
+ }
+
+ @Override
+ protected void onProgressUpdate(String... arg0) {
+ Log.d(TAG, "onProgressUpdate - " + arg0[0]);
+ }
+ }
+
+ private final class AbortResultAsync extends AsyncTask {
+
+ private final String TAG = "AbortResultAsync";
+
+ private String url;
+ private String name;
+
+ @Override
+ protected Boolean doInBackground(String... params) {
+ this.url = params[0];
+ this.name = params[1];
+ publishProgress("doInBackground() - AbortResultAsync url: " + url + " Name: " + name);
+
+ Boolean retry = rpc.resultOp(RpcClient.RESULT_ABORT, url, name);
+ if(retry) {
+ publishProgress("successful.");
+ }
+ return retry;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean success) {
+ forceRefresh();
+ }
+
+ @Override
+ protected void onProgressUpdate(String... arg0) {
+ Log.d(TAG, "onProgressUpdate - " + arg0[0]);
+ }
+ }
+
private final class WriteClientRunModeAsync extends AsyncTask {
private final String TAG = "WriteClientRunModeAsync";
diff --git a/android/BOINC/src/edu/berkeley/boinc/receiver/BootReceiver.java b/android/BOINC/src/edu/berkeley/boinc/receiver/BootReceiver.java
index 9e0b7dced9..ce62d7fe56 100644
--- a/android/BOINC/src/edu/berkeley/boinc/receiver/BootReceiver.java
+++ b/android/BOINC/src/edu/berkeley/boinc/receiver/BootReceiver.java
@@ -22,8 +22,6 @@ import edu.berkeley.boinc.AppPreferences;
import edu.berkeley.boinc.BOINCActivity;
import edu.berkeley.boinc.R;
import edu.berkeley.boinc.client.Monitor;
-import android.app.Notification;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
@@ -34,7 +32,6 @@ import android.util.Log;
public class BootReceiver extends BroadcastReceiver {
private final String TAG = "BOINC BootReceiver";
- private NotificationManager mNM;
@Override
public void onReceive(Context context, Intent intent) {
@@ -48,15 +45,8 @@ public class BootReceiver extends BroadcastReceiver {
//startServiceIntent.putExtra("autostart", true);
context.startService(startServiceIntent);
- mNM = (NotificationManager) context.getSystemService(Service.NOTIFICATION_SERVICE);
- Notification notification = new Notification(R.drawable.boinc, context.getString(R.string.autostart_notification_header), System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(context.getApplicationContext(), 0, new Intent(context.getApplicationContext(), BOINCActivity.class), 0);
- // Set current view for notification panel
- notification.setLatestEventInfo(context.getApplicationContext(), context.getString(R.string.autostart_notification_header), context.getString(R.string.autostart_notification_text), contentIntent);
-
- // Send notification
- mNM.notify(context.getResources().getInteger(R.integer.autostart_notification_id), notification);
} else {
// do nothing
Log.d(TAG,"autostart disabeld");
diff --git a/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java b/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java
index b5243ee9ea..9a4887cf2e 100644
--- a/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java
+++ b/android/BOINC/src/edu/berkeley/boinc/rpc/RpcClient.java
@@ -1103,4 +1103,52 @@ public class RpcClient {
return false;
}
}
+
+ /**
+ * Triggers operation on task in BOINC core client
+ * @param operation operation to be triggered
+ * @param projectUrl master URL of project
+ * @param fileName name of the file
+ * @return true for success, false for failure
+ */
+ public boolean resultOp(int operation, String projectUrl, String resultName) {
+ try {
+ String opTag;
+ switch (operation) {
+ case RESULT_SUSPEND:
+ opTag = "suspend_result";
+ break;
+ case RESULT_RESUME:
+ opTag = "resume_result";
+ break;
+ case RESULT_ABORT:
+ opTag = "abort_result";
+ break;
+ default:
+ if (Logging.ERROR) Log.e(TAG, "resultOp() - unsupported operation: " + operation);
+ return false;
+ }
+ mRequest.setLength(0);
+ mRequest.append("<");
+ mRequest.append(opTag);
+ mRequest.append(">\n ");
+ mRequest.append(projectUrl);
+ mRequest.append("\n ");
+ mRequest.append(resultName);
+ mRequest.append("\n");
+ mRequest.append(opTag);
+ mRequest.append(">\n");
+ 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 transferOp()", e);
+ return false;
+ }
+ }
}