Counter for digesting, stop button, don't stop service while digesting,...

This commit is contained in:
Brad Fitzpatrick 2010-07-25 13:45:09 -07:00
parent c3d41f2329
commit f7d626db42
6 changed files with 131 additions and 28 deletions

View File

@ -7,4 +7,6 @@
<string name="pause_resume">Pause / Resume</string>
<string name="pause">Pause</string>
<string name="resume">Resume</string>
<string name="uploading">Uploading...</string>
<string name="digesting">Digesting...</string>
</resources>

View File

@ -27,6 +27,7 @@ import android.widget.TextView;
public class CamliActivity extends Activity {
private static final String TAG = "CamliActivity";
private static final int MENU_SETTINGS = 1;
private static final int MENU_STOP = 2;
private IUploadService mServiceStub = null;
private IStatusCallback mCallback = null;
@ -90,7 +91,8 @@ public class CamliActivity extends Activity {
});
mCallback = new IStatusCallback.Stub() {
private volatile int mLastBlobsRemain = 0;
private volatile int mLastBlobsUploadRemain = 0;
private volatile int mLastBlobsDigestRemain = 0;
public void logToClient(String stuff) throws RemoteException {
// TODO Auto-generated method stub
@ -102,24 +104,29 @@ public class CamliActivity extends Activity {
public void run() {
if (uploading) {
buttonToggle.setText(R.string.pause);
textStatus.setText("Uploading...");
textStatus.setText(R.string.uploading);
} else if (mLastBlobsDigestRemain > 0) {
buttonToggle.setText(R.string.pause);
textStatus.setText(R.string.digesting);
} else {
buttonToggle.setText(R.string.resume);
textStatus.setText(mLastBlobsRemain > 0 ? "Paused." : "Idle.");
int stepsRemain = mLastBlobsUploadRemain + mLastBlobsDigestRemain;
textStatus.setText(stepsRemain > 0 ? "Paused." : "Idle.");
}
}
});
}
public void setBlobStatus(final int done, final int inFlight, final int total)
public void setBlobStatus(final int blobsDone, final int inFlight, final int total)
throws RemoteException {
mHandler.post(new Runnable() {
public void run() {
buttonToggle.setEnabled(done != total);
boolean finished = (blobsDone == total && mLastBlobsDigestRemain == 0);
buttonToggle.setEnabled(!finished);
progressBlob.setMax(total);
progressBlob.setProgress(done);
progressBlob.setSecondaryProgress(done + inFlight);
if (done == total) {
progressBlob.setProgress(blobsDone);
progressBlob.setSecondaryProgress(blobsDone + inFlight);
if (finished) {
buttonToggle.setText(getString(R.string.pause_resume));
}
}
@ -140,12 +147,20 @@ public class CamliActivity extends Activity {
});
}
public void setBlobsRemain(final int num) throws RemoteException {
public void setBlobsRemain(final int toUpload, final int toDigest)
throws RemoteException {
mHandler.post(new Runnable() {
public void run() {
mLastBlobsRemain = num;
buttonToggle.setEnabled(num != 0);
textBlobsRemain.setText("Blobs remain: " + num);
mLastBlobsUploadRemain = toUpload;
mLastBlobsDigestRemain = toDigest;
buttonToggle.setEnabled((toUpload + toDigest) != 0);
StringBuilder sb = new StringBuilder(40);
sb.append("Blobs to upload: ").append(toUpload);
if (toDigest > 0) {
sb.append("; to digest: ").append(toDigest);
}
textBlobsRemain.setText(sb.toString());
}
});
}
@ -177,6 +192,7 @@ public class CamliActivity extends Activity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE, MENU_STOP, 0, "Stop");
menu.add(Menu.NONE, MENU_SETTINGS, 0, "Settings");
return true;
}
@ -184,6 +200,15 @@ public class CamliActivity extends Activity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_STOP:
try {
if (mServiceStub != null) {
mServiceStub.stopEverything();
}
} catch (RemoteException e) {
// Ignore.
}
break;
case MENU_SETTINGS:
SettingsActivity.show(this);
break;

View File

@ -24,7 +24,7 @@ public class DummyNullCallback extends IStatusCallback.Stub {
}
public void setBlobsRemain(int num) throws RemoteException {
public void setBlobsRemain(int toUpload, int toDigest) throws RemoteException {
// TODO Auto-generated method stub
}

View File

@ -5,7 +5,7 @@ oneway interface IStatusCallback {
void setUploadStatusText(String text);
void setUploading(boolean uploading);
void setBlobsRemain(int num);
void setBlobsRemain(int toUpload, int toDigest);
// done: acknowledged by server
// inFlight: written to the server, but no reply yet (i.e. large HTTP POST body)

View File

@ -24,4 +24,7 @@ interface IUploadService {
// Returns false if server not configured.
boolean enqueueUpload(in Uri uri);
int enqueueUploadList(in List<Uri> uri);
// Stop digesting, stop uploads, clear queues.
void stopEverything();
}

View File

@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import android.app.Service;
import android.content.ContentResolver;
@ -33,6 +34,7 @@ public class UploadService extends Service {
private String mLastUploadStatusText = null;
private int mBytesInFlight = 0;
private int mBlobsInFlight = 0;
private int mBlobsToDigest = 0;
// Stats, all guarded by 'this', and all reset to 0 on queue size transition from 0 -> 1.
private long mBytesTotal = 0;
@ -54,7 +56,11 @@ public class UploadService extends Service {
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "UPLOAD SERVICE onDestroy !!!");
if (mUploadThread != null) {
Log.e(TAG, "Unexpected onDestroy with active upload thread. Killing it.");
mUploadThread.interrupt();
mUploadThread = null;
}
}
@Override
@ -109,6 +115,19 @@ public class UploadService extends Service {
}
}
void broadcastAllState() {
synchronized (this) {
try {
mCallback.setUploading(mUploading);
mCallback.setUploadStatusText(mLastUploadStatusText);
mCallback.setBlobsRemain(mQueueSet.size(), mBlobsToDigest);
} catch (RemoteException e) {
}
}
broadcastBlobStatus();
broadcastByteStatus();
}
void setInFlightBlobs(int v) {
synchronized (this) {
mBlobsInFlight = v;
@ -127,17 +146,32 @@ public class UploadService extends Service {
}
}
void onUploadComplete(QueuedFile qf, boolean wasAlreadyExisting) {
/**
* Callback from the UploadThread to the service.
*
* @param qf
* the queued file
* @param wasUploaded
* not a dupe that the server already had. the bytes were
* actually uploaded.
*/
void onUploadComplete(QueuedFile qf, boolean wasUploaded) {
Log.d(TAG, "onUploadComplete of " + qf + ", uploaded=" + wasUploaded);
synchronized (this) {
if (!mQueueSet.remove(qf)) {
return;
}
mQueueList.remove(qf); // TODO: ghetto, linear scan
mBytesUploaded += qf.getSize();
mBlobsUploaded += 1;
if (wasUploaded) {
mBytesUploaded += qf.getSize();
mBlobsUploaded += 1;
} else {
mBytesTotal -= qf.getSize();
mBlobsTotal -= 1;
}
try {
mCallback.setBlobsRemain(mQueueSet.size());
mCallback.setBlobsRemain(mQueueSet.size(), mBlobsToDigest);
} catch (RemoteException e) {
}
broadcastByteStatus();
@ -148,10 +182,11 @@ public class UploadService extends Service {
private void stopServiceIfEmpty() {
synchronized (this) {
if (mQueueSet.isEmpty()) {
if (mQueueSet.isEmpty() && mBlobsToDigest == 0) {
stopService(new Intent(UploadService.this, UploadService.class));
}
}
}
ParcelFileDescriptor getFileDescriptor(Uri uri) {
@ -166,21 +201,42 @@ public class UploadService extends Service {
private final IUploadService.Stub service = new IUploadService.Stub() {
// Incremented whenever "stop" is pressed:
private final AtomicInteger mStopDigestingCounter = new AtomicInteger(0);
public int enqueueUploadList(List<Uri> uriList) throws RemoteException {
startService(new Intent(UploadService.this, UploadService.class));
Log.d(TAG, "enqueuing list of " + uriList.size() + " URIs");
synchronized (UploadService.this) {
mBlobsToDigest += uriList.size();
mCallback.setBlobsRemain(mQueueSet.size(), mBlobsToDigest);
}
int goodCount = 0;
int startGen = mStopDigestingCounter.get();
for (Uri uri : uriList) {
goodCount += enqueueUpload(uri) ? 1 : 0;
goodCount += enqueueSingleUri(uri) ? 1 : 0;
if (startGen != mStopDigestingCounter.get()) {
return goodCount;
}
}
Log.d(TAG, "...goodCount = " + goodCount);
return goodCount;
}
/*
* Note: blocks while sha1'ing the file. Should be called from an
* AsyncTask from the Activity. TODO: make the activity pass this info
* via a startService(Intent) to us.
*/
public boolean enqueueUpload(Uri uri) throws RemoteException {
startService(new Intent(UploadService.this, UploadService.class));
return enqueueSingleUri(uri);
}
private boolean enqueueSingleUri(Uri uri) throws RemoteException {
ParcelFileDescriptor pfd = getFileDescriptor(uri);
String sha1 = Util.getSha1(pfd.getFileDescriptor());
mBlobsToDigest--;
QueuedFile qf = new QueuedFile(sha1, uri, pfd.getStatSize());
boolean needResume = false;
@ -204,7 +260,7 @@ public class UploadService extends Service {
mBlobsTotal += 1;
needResume = !mUploading;
mCallback.setBlobsRemain(mQueueSet.size());
mCallback.setBlobsRemain(mQueueSet.size(), mBlobsToDigest);
}
broadcastBlobStatus();
broadcastByteStatus();
@ -227,13 +283,8 @@ public class UploadService extends Service {
cb = DummyNullCallback.instance();
}
mCallback = cb;
// Init the new connection.
cb.setUploading(mUploading);
cb.setUploadStatusText(mLastUploadStatusText);
cb.setBlobsRemain(mQueueSet.size());
}
broadcastBlobStatus();
broadcastByteStatus();
broadcastAllState();
}
public void unregisterCallback(IStatusCallback cb) throws RemoteException {
@ -305,5 +356,27 @@ public class UploadService extends Service {
return mQueueList.size();
}
}
public void stopEverything() throws RemoteException {
synchronized (UploadService.this) {
mQueueSet.clear();
mQueueList.clear();
mLastUploadStatusText = "Stopped";
mUploading = false;
mBytesInFlight = 0;
mBlobsInFlight = 0;
mBlobsToDigest = 0;
mBytesTotal = 0;
mBytesUploaded = 0;
mBlobsTotal = 0;
mBlobsUploaded = 0;
mStopDigestingCounter.incrementAndGet();
if (mUploadThread != null) {
mUploadThread.stopPlease();
mUploadThread = null;
}
}
broadcastAllState();
}
};
}