mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 04:43:54 +01:00
Tap to retry failed uploads implemented
UploadService can now be bound to as a local service. Yay!
This commit is contained in:
parent
91aa440eac
commit
297f3277de
6 changed files with 104 additions and 34 deletions
|
|
@ -57,6 +57,8 @@ public class CommonsApplication extends Application {
|
||||||
public static final String API_URL = "https://test.wikipedia.org/w/api.php";
|
public static final String API_URL = "https://test.wikipedia.org/w/api.php";
|
||||||
public static final String IMAGE_URL_BASE = "https://upload.wikimedia.org/wikipedia/test";
|
public static final String IMAGE_URL_BASE = "https://upload.wikimedia.org/wikipedia/test";
|
||||||
|
|
||||||
|
public static final String DEFAULT_EDIT_SUMMARY = "Uploaded using Android Commons app";
|
||||||
|
|
||||||
|
|
||||||
public static MWApi createMWApi() {
|
public static MWApi createMWApi() {
|
||||||
DefaultHttpClient client = new DefaultHttpClient();
|
DefaultHttpClient client = new DefaultHttpClient();
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ import java.util.Date;
|
||||||
|
|
||||||
public class Media implements Serializable {
|
public class Media implements Serializable {
|
||||||
|
|
||||||
|
protected Media() {
|
||||||
|
}
|
||||||
|
|
||||||
public Uri getLocalUri() {
|
public Uri getLocalUri() {
|
||||||
return localUri;
|
return localUri;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,8 @@ public class UploadService extends Service {
|
||||||
|
|
||||||
private int toUpload;
|
private int toUpload;
|
||||||
|
|
||||||
private volatile Looper mServiceLooper;
|
private volatile Looper uploadThreadLooper;
|
||||||
private volatile ServiceHandler mServiceHandler;
|
private volatile ServiceHandler uploadThreadHandler;
|
||||||
private String mName;
|
|
||||||
private boolean mRedelivery;
|
|
||||||
|
|
||||||
private final class ServiceHandler extends Handler {
|
private final class ServiceHandler extends Handler {
|
||||||
public ServiceHandler(Looper looper) {
|
public ServiceHandler(Looper looper) {
|
||||||
|
|
@ -119,14 +117,22 @@ public class UploadService extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
mServiceLooper.quit();
|
uploadThreadLooper.quit();
|
||||||
contributionsProviderClient.release();
|
contributionsProviderClient.release();
|
||||||
Log.d("Commons", "ZOMG I AM BEING KILLED HALP!");
|
Log.d("Commons", "ZOMG I AM BEING KILLED HALP!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class UploadServiceLocalBinder extends Binder {
|
||||||
|
public UploadService getService() {
|
||||||
|
return UploadService.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final IBinder localBinder = new UploadServiceLocalBinder();
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
return null;
|
return localBinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -135,8 +141,8 @@ public class UploadService extends Service {
|
||||||
HandlerThread thread = new HandlerThread("UploadService");
|
HandlerThread thread = new HandlerThread("UploadService");
|
||||||
thread.start();
|
thread.start();
|
||||||
|
|
||||||
mServiceLooper = thread.getLooper();
|
uploadThreadLooper = thread.getLooper();
|
||||||
mServiceHandler = new ServiceHandler(mServiceLooper);
|
uploadThreadHandler = new ServiceHandler(uploadThreadLooper);
|
||||||
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
app = (CommonsApplication) this.getApplicationContext();
|
app = (CommonsApplication) this.getApplicationContext();
|
||||||
contributionsProviderClient = this.getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
|
contributionsProviderClient = this.getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
|
||||||
|
|
@ -179,9 +185,20 @@ public class UploadService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postMessage(int type, Object obj) {
|
private void postMessage(int type, Object obj) {
|
||||||
Message msg = mServiceHandler.obtainMessage(type);
|
Message msg = uploadThreadHandler.obtainMessage(type);
|
||||||
msg.obj = obj;
|
msg.obj = obj;
|
||||||
mServiceHandler.sendMessage(msg);
|
uploadThreadHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void queueContribution(Contribution contribution) {
|
||||||
|
contribution.setState(Contribution.STATE_QUEUED);
|
||||||
|
contribution.setTransferred(0);
|
||||||
|
contribution.setContentProviderClient(contributionsProviderClient);
|
||||||
|
|
||||||
|
contribution.save();
|
||||||
|
|
||||||
|
postMessage(ACTION_UPLOAD_FILE, contribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -193,13 +210,10 @@ public class UploadService extends Service {
|
||||||
notificationManager.notify(NOTIFICATION_UPLOAD_IN_PROGRESS, curProgressNotification);
|
notificationManager.notify(NOTIFICATION_UPLOAD_IN_PROGRESS, curProgressNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d("Commons", "Received startcommand");
|
||||||
Contribution contribution = mediaFromIntent(intent);
|
Contribution contribution = mediaFromIntent(intent);
|
||||||
contribution.setState(Contribution.STATE_QUEUED);
|
queueContribution(contribution);
|
||||||
contribution.setContentProviderClient(contributionsProviderClient);
|
|
||||||
|
|
||||||
contribution.save();
|
|
||||||
|
|
||||||
postMessage(ACTION_UPLOAD_FILE, contribution);
|
|
||||||
return START_REDELIVER_INTENT;
|
return START_REDELIVER_INTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import java.util.*;
|
||||||
|
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.net.*;
|
import android.net.*;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
|
@ -34,7 +35,7 @@ public class Contribution extends Media {
|
||||||
private long transferred;
|
private long transferred;
|
||||||
|
|
||||||
public String getEditSummary() {
|
public String getEditSummary() {
|
||||||
return editSummary;
|
return editSummary != null ? editSummary : CommonsApplication.DEFAULT_EDIT_SUMMARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getContentUri() {
|
public Uri getContentUri() {
|
||||||
|
|
@ -142,6 +143,26 @@ public class Contribution extends Media {
|
||||||
this.imageUrl = imageUrl;
|
this.imageUrl = imageUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Contribution() {
|
||||||
|
// Empty constructor for being constructed by our static methods
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Contribution fromCursor(Cursor cursor) {
|
||||||
|
// Hardcoding column positions!
|
||||||
|
Contribution c = new Contribution();
|
||||||
|
c.contentUri = ContributionsContentProvider.uriForId(cursor.getInt(0));
|
||||||
|
c.filename = cursor.getString(1);
|
||||||
|
c.localUri = TextUtils.isEmpty(cursor.getString(2)) ? null : Uri.parse(cursor.getString(2));
|
||||||
|
c.imageUrl = cursor.getString(3);
|
||||||
|
c.timestamp = cursor.getLong(4) == 0 ? null : new Date(cursor.getLong(4));
|
||||||
|
c.state = cursor.getInt(5);
|
||||||
|
c.dataLength = cursor.getLong(6);
|
||||||
|
c.dateUploaded = cursor.getLong(7) == 0 ? null : new Date(cursor.getLong(7));
|
||||||
|
c.transferred = cursor.getLong(8);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class Table {
|
public static class Table {
|
||||||
public static final String TABLE_NAME = "contributions";
|
public static final String TABLE_NAME = "contributions";
|
||||||
|
|
@ -156,6 +177,19 @@ public class Contribution extends Media {
|
||||||
public static final String COLUMN_UPLOADED = "uploaded";
|
public static final String COLUMN_UPLOADED = "uploaded";
|
||||||
public static final String COLUMN_TRANSFERRED = "transferred"; // Currently transferred number of bytes
|
public static final String COLUMN_TRANSFERRED = "transferred"; // Currently transferred number of bytes
|
||||||
|
|
||||||
|
// NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES.
|
||||||
|
public static final String[] ALL_FIELDS = {
|
||||||
|
COLUMN_ID,
|
||||||
|
COLUMN_FILENAME,
|
||||||
|
COLUMN_LOCAL_URI,
|
||||||
|
COLUMN_IMAGE_URL,
|
||||||
|
COLUMN_TIMESTAMP,
|
||||||
|
COLUMN_STATE,
|
||||||
|
COLUMN_LENGTH,
|
||||||
|
COLUMN_UPLOADED,
|
||||||
|
COLUMN_TRANSFERRED
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
private static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " ("
|
private static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " ("
|
||||||
+ "_id INTEGER PRIMARY KEY,"
|
+ "_id INTEGER PRIMARY KEY,"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package org.wikimedia.commons.contributions;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
|
|
@ -17,10 +18,7 @@ import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.GridView;
|
import android.widget.*;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
import com.actionbarsherlock.app.SherlockFragmentActivity;
|
||||||
import com.actionbarsherlock.view.ActionMode;
|
import com.actionbarsherlock.view.ActionMode;
|
||||||
import com.actionbarsherlock.view.Menu;
|
import com.actionbarsherlock.view.Menu;
|
||||||
|
|
@ -53,6 +51,18 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
|
||||||
super(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
|
super(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UploadService uploadService;
|
||||||
|
private ServiceConnection uploadServiceConnection = new ServiceConnection() {
|
||||||
|
public void onServiceConnected(ComponentName componentName, IBinder binder) {
|
||||||
|
uploadService = ((UploadService.UploadServiceLocalBinder)binder).getService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName componentName) {
|
||||||
|
// this should never happen
|
||||||
|
throw new RuntimeException("UploadService died but the rest of the process did not!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private class ContributionAdapter extends CursorAdapter {
|
private class ContributionAdapter extends CursorAdapter {
|
||||||
|
|
||||||
private final int COLUMN_FILENAME;
|
private final int COLUMN_FILENAME;
|
||||||
|
|
@ -127,17 +137,6 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
|
||||||
|
|
||||||
private DisplayImageOptions contributionDisplayOptions;
|
private DisplayImageOptions contributionDisplayOptions;
|
||||||
|
|
||||||
private String[] CONTRIBUTIONS_PROJECTION = {
|
|
||||||
Contribution.Table.COLUMN_ID,
|
|
||||||
Contribution.Table.COLUMN_FILENAME,
|
|
||||||
Contribution.Table.COLUMN_LOCAL_URI,
|
|
||||||
Contribution.Table.COLUMN_STATE,
|
|
||||||
Contribution.Table.COLUMN_UPLOADED,
|
|
||||||
Contribution.Table.COLUMN_LENGTH,
|
|
||||||
Contribution.Table.COLUMN_TRANSFERRED,
|
|
||||||
Contribution.Table.COLUMN_IMAGE_URL
|
|
||||||
};
|
|
||||||
|
|
||||||
private String CONTRIBUTION_SELECTION = "";
|
private String CONTRIBUTION_SELECTION = "";
|
||||||
/*
|
/*
|
||||||
This sorts in the following order:
|
This sorts in the following order:
|
||||||
|
|
@ -171,11 +170,25 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
|
||||||
.cacheOnDisc()
|
.cacheOnDisc()
|
||||||
.resetViewBeforeLoading().build();
|
.resetViewBeforeLoading().build();
|
||||||
|
|
||||||
Cursor allContributions = getContentResolver().query(ContributionsContentProvider.BASE_URI, CONTRIBUTIONS_PROJECTION, CONTRIBUTION_SELECTION, null, CONTRIBUTION_SORT);
|
bindService(new Intent(this, UploadService.class), uploadServiceConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
|
Cursor allContributions = getContentResolver().query(ContributionsContentProvider.BASE_URI, Contribution.Table.ALL_FIELDS, CONTRIBUTION_SELECTION, null, CONTRIBUTION_SORT);
|
||||||
contributionsAdapter = new ContributionAdapter(this, allContributions, 0);
|
contributionsAdapter = new ContributionAdapter(this, allContributions, 0);
|
||||||
contributionsList.setAdapter(contributionsAdapter);
|
contributionsList.setAdapter(contributionsAdapter);
|
||||||
|
|
||||||
getSupportLoaderManager().initLoader(0, null, this);
|
getSupportLoaderManager().initLoader(0, null, this);
|
||||||
|
|
||||||
|
contributionsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
|
public void onItemClick(AdapterView<?> adapterView, View view, int position, long item) {
|
||||||
|
Cursor cursor = (Cursor)adapterView.getItemAtPosition(position);
|
||||||
|
Contribution c = Contribution.fromCursor(cursor);
|
||||||
|
if(c.getState() == Contribution.STATE_FAILED) {
|
||||||
|
uploadService.queueContribution(c);
|
||||||
|
Log.d("Commons", "Restarting for" + c.toContentValues().toString());
|
||||||
|
}
|
||||||
|
Log.d("Commons", "You clicked on:" + c.toContentValues().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -283,7 +296,7 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
|
||||||
}
|
}
|
||||||
|
|
||||||
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
|
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
|
||||||
return new CursorLoader(this, ContributionsContentProvider.BASE_URI, CONTRIBUTIONS_PROJECTION, CONTRIBUTION_SELECTION, null, CONTRIBUTION_SORT);
|
return new CursorLoader(this, ContributionsContentProvider.BASE_URI, Contribution.Table.ALL_FIELDS, CONTRIBUTION_SELECTION, null, CONTRIBUTION_SORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
|
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,14 @@ public class ContributionsContentProvider extends ContentProvider{
|
||||||
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||||
static {
|
static {
|
||||||
uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTRIBUTIONS);
|
uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTRIBUTIONS);
|
||||||
uriMatcher.addURI(AUTHORITY, BASE_PATH + "/*", CONTRIBUTIONS_ID);
|
uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTRIBUTIONS_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Uri uriForId(int id) {
|
||||||
|
return Uri.parse(BASE_URI.toString() + "/" + id);
|
||||||
|
}
|
||||||
|
|
||||||
private DBOpenHelper dbOpenHelper;
|
private DBOpenHelper dbOpenHelper;
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreate() {
|
public boolean onCreate() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue