Commit 86cff479 authored by Alan McNatty's avatar Alan McNatty
Browse files

Merge branch 'master' of https://code.google.com/p/maharadroid

parents f4db6242 26d1b788
......@@ -5,3 +5,4 @@ gen
local.properties
build
trunk
/.settings
......@@ -225,10 +225,6 @@ public class Artefact extends Object implements Parcelable {
time = System.currentTimeMillis();
}
public Artefact(Context mContext, Long id) {
// TODO Auto-generated constructor stub
load(mContext, id);
}
public void upload(Boolean auto, Context mContext) {
Intent i = new Intent(mContext, TransferService.class);
i.putExtra("artefact", (Parcelable) this);
......@@ -250,7 +246,6 @@ public class Artefact extends Object implements Parcelable {
mContext.startActivity(i);
}
public void save(Context mContext) {
// TODO Auto-generated method stub
ArtefactDataSQLHelper artefactData = new ArtefactDataSQLHelper(mContext);
if ( id != 0 ) { // update
Log.d("Artefact", "save: is_draft: " + is_draft);
......@@ -263,9 +258,8 @@ public class Artefact extends Object implements Parcelable {
artefactData.close();
}
public void load(Context mContext, Long id) {
// TODO Auto-generated method stub
ArtefactDataSQLHelper artefactData = new ArtefactDataSQLHelper(mContext);
artefactData.loadSavedArtefacts(id);
artefactData.loadSavedArtefact(id);
artefactData.close();
}
public String getFilePath(Context context) {
......
......@@ -102,65 +102,79 @@ public class ArtefactDataSQLHelper extends SQLiteOpenHelper {
}
}
public void uploadAllSavedArtefacts(Boolean uploaded) {
SQLiteDatabase db = this.getReadableDatabase();
if ( uploaded == null ) {
uploaded = false;
}
Cursor cursor = db.query(ArtefactDataSQLHelper.TABLE, null, null, null, null,
null, null);
if ( VERBOSE ) Log.v(TAG, "uploadAllSavedArtefacts: returned " + cursor.getCount() + " records.");
while (cursor.moveToNext()) {
Artefact a = createArtefactFromCursor(cursor);
a.upload(true, mContext);
public void uploadAllSavedArtefacts() {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(ArtefactDataSQLHelper.TABLE, null, null, null, null, null, null);
try {
if (VERBOSE) Log.v(TAG, "uploadAllSavedArtefacts: returned " + cursor.getCount() + " records.");
while (cursor.moveToNext()) {
Artefact a = createArtefactFromCursor(cursor);
a.upload(true, mContext);
}
} finally {
cursor.close();
}
}
public Artefact loadSavedArtefacts(Long id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(ArtefactDataSQLHelper.TABLE, null, BaseColumns._ID + " = ?", new String[] { id.toString() },
null, null, null);
if ( cursor == null )
return null;
cursor.moveToFirst();
return createArtefactFromCursor(cursor);
public Artefact loadSavedArtefact(Long id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(ArtefactDataSQLHelper.TABLE, null, BaseColumns._ID + " = ?",
new String[] { id.toString() }, null, null, null);
try {
if (cursor == null)
return null;
cursor.moveToFirst();
return createArtefactFromCursor(cursor);
} finally {
cursor.close();
}
}
public Artefact[] loadSavedArtefacts() {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(ArtefactDataSQLHelper.TABLE, null, null, null, null, null, null);
//startManagingCursor(cursor);
if ( cursor == null )
return new Artefact[] {};// TODO why different from above?
SQLiteDatabase db = this.getReadableDatabase();
//startManagingCursor(cursor);
Artefact[] a_array = new Artefact[cursor.getCount()];
int items = 0;
while (cursor.moveToNext()) {
Artefact a = createArtefactFromCursor(cursor);
// Only include artefacts with either no attached file or valid files (may have been deleted in the background so we check)
if ( a.getFilename() == null ||
( a.getFilename() != null && a.getFilePath(mContext) != null ) ) {
a_array[items++] = a;
} else {
Log.i(TAG, "Artefact '" + a.getTitle() +
"' file [" + a.getFilename() +
"] no longer exists, deleting from saved artefacts");
this.deleteSavedArtefact(a.getId());
Cursor cursor = db.query(ArtefactDataSQLHelper.TABLE, null, null, null, null, null, null);
try {
if (cursor == null)
return new Artefact[] {};// TODO why different from above?
Artefact[] a_array = new Artefact[cursor.getCount()];
int items = 0;
while (cursor.moveToNext()) {
Artefact a = createArtefactFromCursor(cursor);
// Only include artefacts with either no attached file or valid
// files (may have been deleted in the background so we check)
if (a.getFilename() == null
|| (a.getFilename() != null && a.getFilePath(mContext) != null)) {
a_array[items++] = a;
} else {
Log.i(TAG, "Artefact '" + a.getTitle() + "' file [" + a.getFilename()
+ "] no longer exists, deleting from saved artefacts");
this.deleteSavedArtefact(a.getId());
}
}
return a_array;
} finally {
cursor.close();
}
return a_array;
}
private Artefact createArtefactFromCursor(Cursor cursor) {
if ( VERBOSE ) Log.v(TAG, "createArtefactFromCursor draft: " + cursor.getInt(8));
if ( VERBOSE ) Log.v(TAG, "createArtefactFromCursor allow comments: " + cursor.getInt(9));
......
......@@ -18,7 +18,6 @@ public class MaharaProvider extends ContentProvider {
private static final String DATABASE_NAME = "maharadroid_sync.db";
private static final int DATABASE_VERSION = 1;
private static final String TAG = "MyContentProvider";
private static class DatabaseHelper extends SQLiteOpenHelper {
......
......@@ -105,7 +105,7 @@ public class ThreadedSyncAdapter extends AbstractThreadedSyncAdapter{
if ( VERBOSE ) Log.v(TAG, "onPerformSync: canUpload so uploadAllSavedArtefacts");
ArtefactDataSQLHelper artefactData = new ArtefactDataSQLHelper(mContext);
artefactData.uploadAllSavedArtefacts(false);
artefactData.uploadAllSavedArtefacts();
artefactData.close();
}
} else {
......
......@@ -175,7 +175,7 @@ public class ArtefactExpandableListAdapterActivity extends Activity implements O
loadSavedArtefacts();
break;
case R.id.option_upload:
artefactData.uploadAllSavedArtefacts(true);
artefactData.uploadAllSavedArtefacts();
loadSavedArtefacts();
break;
case R.id.about:
......
......@@ -54,7 +54,7 @@ import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
/*
/**
* The ArtifactSettings class is based on the PictureSettings class,
* it has been modified to only support upload components. The original was
* written by Russel Stewart (rnstewart@gmail.com) as part of the Flickr Free
......@@ -62,7 +62,6 @@ import android.widget.Toast;
*
* @author Alan McNatty (alan.mcnatty@catalyst.net.nz)
*/
public class ArtifactSettingsActivity extends Activity implements OnClickListener {
static final String TAG = LogConfig.getLogTag(ArtifactSettingsActivity.class);
......@@ -287,7 +286,6 @@ public class ArtifactSettingsActivity extends Activity implements OnClickListene
boolean allow_comments = ((CheckBox) findViewById(R.id.txtArtefactAllowComments)).isChecked();
if ( id != null && id.length() > 0 ) {
a.load(mContext, Long.valueOf(id));
a.setTitle(title);
a.setDescription(description);
a.setTags(tags);
......@@ -489,7 +487,7 @@ public class ArtifactSettingsActivity extends Activity implements OnClickListene
tgs.setText(TextUtils.join(",", new_tags));
}
public void onNothingSelected(AdapterView parent) {
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing.
}
}
......@@ -503,7 +501,7 @@ public class ArtifactSettingsActivity extends Activity implements OnClickListene
l.setVisibility( pos > 0 ? LinearLayout.VISIBLE : LinearLayout.GONE );
}
public void onNothingSelected(AdapterView parent) {
public void onNothingSelected(AdapterView<?> parent) {
LinearLayout l;
l = (LinearLayout) findViewById(R.id.ArtefactJournalExtrasLayout);
l.setVisibility( LinearLayout.GONE );
......
......@@ -21,8 +21,6 @@
package nz.net.catalyst.MaharaDroid.upload;
import java.util.LinkedList;
import nz.net.catalyst.MaharaDroid.GlobalResources;
import nz.net.catalyst.MaharaDroid.LogConfig;
import nz.net.catalyst.MaharaDroid.R;
......@@ -33,225 +31,140 @@ import nz.net.catalyst.MaharaDroid.upload.http.RestClient;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
public class TransferService extends Service {
public class TransferService extends IntentService {
static final String TAG = LogConfig.getLogTag(TransferService.class);
// whether DEBUG level logging is enabled (whether globally, or explicitly for this log tag)
static final boolean DEBUG = LogConfig.isDebug(TAG);
// whether VERBOSE level logging is enabled
static final boolean VERBOSE = LogConfig.VERBOSE;
private final IBinder m_binder = new TransferServiceBinder();
private UploadArtifactTask m_upload_task = null;
private Context mContext;
private int activeUploads = 0;
public TransferService() {
super("Transfer Service");
}
@Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
// AsyncTask to upload a picture in the background.
private class UploadArtifactTask extends AsyncTask<Void, String, Object> {
@Override
protected void onHandleIntent(Intent intent) {
@Override
protected Object doInBackground(Void... params) {
Bundle upload_info = null;
mContext = getApplicationContext();
while (m_uploads.size() > 0) {
upload_info = m_uploads.get(0);
if (upload_info != null) {
Artefact a = upload_info.getParcelable("artefact");
String id = String.valueOf((int) (System.currentTimeMillis() / 1000L));
//if ( VERBOSE ) Log.v(TAG, "id = " + id);
publishProgress(new String[]{"start", id, a.getTitle()});
JSONObject result = RestClient.UploadArtifact(
getUploadURLPref(),
getUploadAuthTokenPref(),
getUploadUsernamePref(),
a.getJournalId(),
a.getIsDraft(), a.getAllowComments(),
getUploadFolderPref(),
getUploadTagsPref(a.getTags()),
a.getFilePath(mContext),
a.getTitle(),
a.getDescription(),
mContext);
m_uploads.remove();
if (result == null || result.has("fail")) {
String err_str = null;
try {
err_str = (result == null) ? "Unknown Failure" : result.getString("fail");
} catch (JSONException e) {
err_str = "Unknown Failure";
}
a.save(mContext);
publishProgress("fail", id, err_str);
//m_uploads.clear();
} else if ( result.has("success") ) {
Utils.updateTokenFromResult(result, mContext);
a.delete(mContext);
publishProgress(new String[]{"finish", id, a.getTitle()});
}
}
}
return null;
Bundle upload_info = intent.getExtras();
if (upload_info == null) {
return;
}
@Override
protected void onProgressUpdate(String... progress) {
mContext = getApplicationContext();
// onProgressUpdate is called each time a new upload starts. This allows
// us to update the notification text to let the user know which picture
// is being uploaded.
if (progress.length > 2) {
String status = progress[0];
Integer id = Integer.valueOf(progress[1]);
//if ( VERBOSE ) Log.v(TAG, "onProgressUpdate id = " + id);
if ( id == null ) id = 0;
if (status.equals("start")) {
activeUploads++;
showUploadNotification(GlobalResources.UPLOADING_ID, activeUploads + " uploading ... ", null);
}
if (status.equals("finish")) {
activeUploads--;
if ( activeUploads <= 0 ) {
cancelNotification(GlobalResources.UPLOADING_ID);
} else {
showUploadNotification(GlobalResources.UPLOADING_ID, activeUploads + " uploading ... ", null);
}
Utils.showNotification(GlobalResources.UPLOADER_ID, progress[2] + " uploaded successfully", null, null, mContext);
}
else if (status == "fail") {
activeUploads--;
if ( activeUploads <= 0 ) {
cancelNotification(GlobalResources.UPLOADING_ID);
} else {
showUploadNotification(GlobalResources.UPLOADING_ID, activeUploads + " uploading ... ", null);
}
Utils.showNotification(GlobalResources.UPLOADER_ID+id, progress[2] + " failed to upload", null, null, mContext);
// stopSelf();
}
Artefact a = upload_info.getParcelable("artefact");
int id = (int) (System.currentTimeMillis() / 1000L);
//if ( VERBOSE ) Log.v(TAG, "id = " + id);
publishProgress("start", id, a.getTitle());
JSONObject result = RestClient.UploadArtifact(
getUploadURLPref(),
getUploadAuthTokenPref(),
getUploadUsernamePref(),
a.getJournalId(),
a.getIsDraft(), a.getAllowComments(),
getUploadFolderPref(),
getUploadTagsPref(a.getTags()),
a.getFilePath(mContext),
a.getTitle(),
a.getDescription(),
mContext);
if (result == null || result.has("fail")) {
String err_str = null;
try {
err_str = (result == null) ? "Unknown Failure" : result.getString("fail");
} catch (JSONException e) {
err_str = "Unknown Failure";
}
a.save(mContext);
publishProgress("fail", id, err_str);
//m_uploads.clear();
} else if ( result.has("success") ) {
Utils.updateTokenFromResult(result, mContext);
a.delete(mContext);
publishProgress("finish", id, a.getTitle());
}
private void showUploadNotification(int id, CharSequence title, CharSequence description) {
mContext = getApplicationContext();
NotificationManager mNM = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(android.R.drawable.stat_sys_upload, title,
System.currentTimeMillis());
PendingIntent contentIntent = null;
// The PendingIntent to launch our activity if the user selects this notification
contentIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
if ( description == null ) {
description = title;
}
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(mContext, title, description, contentIntent);
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Send the notification.
mNM.notify(id, notification);
}
private void cancelNotification(int id) {
NotificationManager mNM = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNM.cancel(id);
}
}
private void publishProgress(String status, int id, String title) {
@Override
protected void onPreExecute() {
}
// update the notification text to let the user know which picture
// is being uploaded.
@Override
protected void onPostExecute(Object result) {
stopSelf();
if (status.equals("start")) {
activeUploads++;
showUploadNotification(GlobalResources.UPLOADING_ID, activeUploads + " uploading ... ", null);
}
public void addUpload(Bundle upload_info) {
if (m_uploads == null) {
m_uploads = new LinkedList<Bundle>();
if (status.equals("finish")) {
activeUploads--;
if ( activeUploads <= 0 ) {
cancelNotification(GlobalResources.UPLOADING_ID);
} else {
showUploadNotification(GlobalResources.UPLOADING_ID, activeUploads + " uploading ... ", null);
}
m_uploads.add(upload_info);
Utils.showNotification(GlobalResources.UPLOADER_ID, title + " uploaded successfully", null, null, getApplicationContext());
}
public LinkedList<Bundle> getUploads() {
return new LinkedList<Bundle>(m_uploads);
else if (status == "fail") {
activeUploads--;
if ( activeUploads <= 0 ) {
cancelNotification(GlobalResources.UPLOADING_ID);
} else {
showUploadNotification(GlobalResources.UPLOADING_ID, activeUploads + " uploading ... ", null);
}
Utils.showNotification(GlobalResources.UPLOADER_ID+id, title + " failed to upload", null, null, getApplicationContext());
}
private LinkedList<Bundle> m_uploads = null;
}
public class TransferServiceBinder extends Binder {
public TransferService getService() {
return TransferService.this;
}
}
@Override
public void onDestroy () {
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
Bundle extras = intent.getExtras();
if (extras != null) {
addUpload(intent.getExtras());
private void showUploadNotification(int id, CharSequence title, CharSequence description) {
NotificationManager mNM = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(android.R.drawable.stat_sys_upload, title,
System.currentTimeMillis());
PendingIntent contentIntent = null;
// The PendingIntent to launch our activity if the user selects this notification
contentIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
if (description == null) {
description = title;
}
}
@Override
public IBinder onBind(Intent arg0) {
return m_binder;
}
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(mContext, title, description, contentIntent);
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
public void addUpload(Bundle upload_info) {
if (m_upload_task == null || (m_upload_task.getStatus() == AsyncTask.Status.FINISHED)) {
// If the upload task has not yet been created or if it is finished, then create
// a new upload task, add the upload to it, and execute.
m_upload_task = (UploadArtifactTask)new UploadArtifactTask();
m_upload_task.addUpload(upload_info);
m_upload_task.execute();
}
else {
// Otherwise, the upload task is currently running, so add the new upload to the
// list.
m_upload_task.addUpload(upload_info);
}
// Send the notification.
mNM.notify(id, notification);
}
public LinkedList<Bundle> getUploads() {
if (m_upload_task == null) {
return new LinkedList<Bundle>();
}
else {
return m_upload_task.getUploads();
}
private void cancelNotification(int id) {
NotificationManager mNM = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNM.cancel(id);
}
private String getUploadURLPref() {
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
......@@ -260,9 +173,9 @@ public class TransferService extends Service {
private String getUploadFolderPref() {
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
if ( mPrefs.getBoolean(mContext.getResources().getString(R.string.pref_upload_folder_default_key), false) ) {
return mPrefs.getString(mContext.getResources().getString(R.string.pref_upload_folder_key), "");
}
if ( mPrefs.getBoolean(mContext.getResources().getString(R.string.pref_upload_folder_default_key), false) ) {
return mPrefs.getString(mContext.getResources().getString(R.string.pref_upload_folder_key), "");
}
return "";
}
private String getUploadAuthTokenPref() {
......@@ -279,6 +192,7 @@ public class TransferService extends Service {