/**
* Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazonaws.mobileconnectors.s3.transferutility;
import android.database.Cursor;
import java.io.File;
/**
* TransferObserver is used to track state and progress of a transfer.
* Applications can set a listener and will get notified when progress or state
* changes.
* <p>
* For example, you can track the progress of an upload as the following:
* </p>
*
* <pre>
* TransferObserver transfer = transferUtility.upload(bucket, key, file);
* transfer.setListener(new TransferListener() {
* public onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
* // update progress bar
* progressBar.setProgress(bytesCurrent);
* }
*
* public void onStateChanged(int id, TransferState state) {
* }
*
* public void onError(int id, Exception ex) {
* }
* });
* </pre>
* <p>
* Note that callbacks of a listener will be invoked on the main thread.
* </p>
*/
public class TransferObserver {
private final int id;
private final TransferDBUtil dbUtil;
private String bucket;
private String key;
private long bytesTotal;
private long bytesTransferred;
private TransferState transferState;
private String filePath;
private TransferListener transferListener;
private TransferStatusListener statusListener;
/**
* Constructs a TransferObserver and initializes fields with the given
* arguments.
*
* @param id The transfer id of the transfer to be observed.
* @param dbUtil an instance of database utility
* @param bucket bucket of the S3 object
* @param key key of the S3 object
* @param file a file associated with this transfer
*/
TransferObserver(int id, TransferDBUtil dbUtil, String bucket, String key, File file) {
this.id = id;
this.dbUtil = dbUtil;
this.bucket = bucket;
this.key = key;
filePath = file.getAbsolutePath();
bytesTotal = file.length();
transferState = TransferState.WAITING;
}
/**
* Constructs a TransferObserver and initializes fields with the given
* arguments.
*
* @param id The transfer id of the transfer to be observed.
* @param dbUtil an instance of database utility
* @param c a cursor to read the state of the transfer from
*/
TransferObserver(int id, TransferDBUtil dbUtil, Cursor c) {
this.id = id;
this.dbUtil = dbUtil;
updateFromDB(c);
}
/**
* Refresh fields in the TransferObserver from the running transfer task. If
* TransferListener is set, then there's no need to call this method.
*/
public void refresh() {
final Cursor c = dbUtil.queryTransferById(id);
try {
if (c.moveToFirst()) {
updateFromDB(c);
}
} finally {
c.close();
}
}
/**
* Update transfer state from the given cursor.
*
* @param c a cursor to read the state of the transfer from
*/
private void updateFromDB(Cursor c) {
bucket = c.getString(c.getColumnIndexOrThrow(TransferTable.COLUMN_BUCKET_NAME));
key = c.getString(c.getColumnIndexOrThrow(TransferTable.COLUMN_KEY));
bytesTotal = c.getLong(c.getColumnIndexOrThrow(TransferTable.COLUMN_BYTES_TOTAL));
bytesTransferred = c.getLong(c
.getColumnIndexOrThrow(TransferTable.COLUMN_BYTES_CURRENT));
transferState = TransferState.getState(c.getString(c
.getColumnIndexOrThrow(TransferTable.COLUMN_STATE)));
filePath = c.getString(c.getColumnIndexOrThrow(TransferTable.COLUMN_FILE));
}
/**
* Sets a listener used to receive notification when state or progress
* changes.
* <p>
* Note that callbacks of the listener will be invoked on the main thread.
* </p>
*
* @param listener A TransferListener used to receive notification.
*/
public void setTransferListener(TransferListener listener) {
synchronized (this) {
// Remove previous listener.
cleanTransferListener();
// One additional listener is attached so that the basic transfer
// info gets updated along side.
statusListener = new TransferStatusListener();
TransferStatusUpdater.registerListener(id, statusListener);
transferListener = listener;
TransferStatusUpdater.registerListener(id, transferListener);
}
}
/**
* Gets the transfer id of the record.
*
* @return The transfer id.
*/
public int getId() {
return id;
}
/**
* Gets the bucket name of the record.
*
* @return The bucket name of the record.
*/
public String getBucket() {
return bucket;
}
/**
* Gets the key of the record.
*
* @return The key of the record.
*/
public String getKey() {
return key;
}
/**
* Gets the total bytes to transfer.
*
* @return The total bytes of the transfer.
*/
public long getBytesTotal() {
return bytesTotal;
}
/**
* Gets the absolute path of file to transfer.
*
* @return The absolute path of the file transferred.
*/
public String getAbsoluteFilePath() {
return filePath;
}
/**
* Gets the bytes transferred currently.
*
* @return The bytes currently transferred.
*/
public long getBytesTransferred() {
return bytesTransferred;
}
/**
* Gets the state of the transfer task.
*
* @return The current state of the transfer.
*/
public TransferState getState() {
return transferState;
}
/**
* Cleans the transfer listener.
*/
public void cleanTransferListener() {
synchronized (this) {
if (transferListener != null) {
TransferStatusUpdater.unregisterListener(id, transferListener);
transferListener = null;
}
if (statusListener != null) {
TransferStatusUpdater.unregisterListener(id, statusListener);
statusListener = null;
}
}
}
/**
* A listener that can update the {@link TransferObserver}.
*/
private class TransferStatusListener implements TransferListener {
@Override
public void onStateChanged(int id, TransferState state) {
transferState = state;
}
@Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
TransferObserver.this.bytesTransferred = bytesCurrent;
TransferObserver.this.bytesTotal = bytesTotal;
}
@Override
public void onError(int id, Exception ex) {
// do nothing
}
}
}