diff --git a/src/android/AckDatabase.java b/src/android/AckDatabase.java index ac4cc3ed..283ab98a 100644 --- a/src/android/AckDatabase.java +++ b/src/android/AckDatabase.java @@ -2,22 +2,34 @@ import android.content.Context; +import androidx.annotation.NonNull; import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; import androidx.room.TypeConverters; +import androidx.room.migration.Migration; +import androidx.sqlite.db.SupportSQLiteDatabase; import androidx.work.Data; -@Database(entities = {UploadEvent.class}, version = 5) +@Database(entities = {UploadEvent.class}, version = 6) @TypeConverters(value = {Data.class}) public abstract class AckDatabase extends RoomDatabase { private static AckDatabase instance; - public static AckDatabase getInstance(final Context context) { + static final Migration MIGRATION_5_6 = new Migration(5, 6) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // Add the new column to the existing table + database.execSQL("ALTER TABLE upload_events ADD COLUMN uploadDuration INTEGER NOT NULL DEFAULT 0"); + } + }; + + public static synchronized AckDatabase getInstance(final Context context) { if (instance == null) { instance = Room .databaseBuilder(context, AckDatabase.class, "cordova-plugin-background-upload.db") .fallbackToDestructiveMigration() + .addMigrations(MIGRATION_5_6) .build(); } return instance; diff --git a/src/android/FileTransferBackground.java b/src/android/FileTransferBackground.java index 8cb6c393..cf0d55e1 100644 --- a/src/android/FileTransferBackground.java +++ b/src/android/FileTransferBackground.java @@ -81,7 +81,7 @@ private void sendProgress(final String id, int progressPercent) { } } - private void sendSuccess(final String id, final String response, int statusCode) { + private void sendSuccess(final String id, final String response, int statusCode, long uploadDuration) { if (response != null && !response.isEmpty()) { logMessage("eventLabel='Uploader onSuccess' uploadId='" + id + "' response='" + response.substring(0, Math.min(2000, response.length() - 1)) + "'"); } else { @@ -95,6 +95,7 @@ private void sendSuccess(final String id, final String response, int statusCode) .put("state", "UPLOADED") .put("serverResponse", response) .put("statusCode", statusCode) + .put("uploadDuration", uploadDuration) ); } catch (JSONException e) { // Can't really happen but just in case @@ -412,7 +413,8 @@ private void handleAck(final Data ackData) { sendSuccess( ackData.getString(UploadTask.KEY_OUTPUT_ID), response, - ackData.getInt(UploadTask.KEY_OUTPUT_STATUS_CODE, -1 /* If this is sent, something is really wrong */) + ackData.getInt(UploadTask.KEY_OUTPUT_STATUS_CODE, -1 /* If this is sent, something is really wrong */), + ackData.getLong(UploadTask.KEY_OUTPUT_UPLOAD_DURATION, 0) ); } else { diff --git a/src/android/UploadEvent.java b/src/android/UploadEvent.java index 33cf12f7..be079e02 100644 --- a/src/android/UploadEvent.java +++ b/src/android/UploadEvent.java @@ -11,6 +11,7 @@ public class UploadEvent { @PrimaryKey @NonNull private String id; + private long uploadDuration; @ColumnInfo(name = "output_data") @NonNull @@ -19,6 +20,7 @@ public class UploadEvent { public UploadEvent(@NonNull final String id, @NonNull final Data outputData) { this.id = id; this.outputData = outputData; + this.uploadDuration = outputData.getLong(UploadTask.KEY_OUTPUT_UPLOAD_DURATION, 0); } @NonNull @@ -30,4 +32,12 @@ public String getId() { public Data getOutputData() { return outputData; } + + public long getUploadDuration() { + return uploadDuration; + } + + public void setUploadDuration(long uploadDuration) { + this.uploadDuration = uploadDuration; + } } diff --git a/src/android/UploadEventDao.java b/src/android/UploadEventDao.java index fade69d9..f7023939 100644 --- a/src/android/UploadEventDao.java +++ b/src/android/UploadEventDao.java @@ -5,6 +5,7 @@ import androidx.room.Insert; import androidx.room.OnConflictStrategy; import androidx.room.Query; +import androidx.room.Update; import java.util.List; @@ -32,4 +33,7 @@ default void delete(final String id) { delete(ack); } } + + @Update + void update(UploadEvent uploadEvent); } diff --git a/src/android/UploadTask.java b/src/android/UploadTask.java index 919f6e9f..e5058895 100644 --- a/src/android/UploadTask.java +++ b/src/android/UploadTask.java @@ -79,6 +79,8 @@ public final class UploadTask extends Worker { public static final String KEY_OUTPUT_STATUS_CODE = "output_status_code"; public static final String KEY_OUTPUT_FAILURE_REASON = "output_failure_reason"; public static final String KEY_OUTPUT_FAILURE_CANCELED = "output_failure_canceled"; + public static final String KEY_OUTPUT_UPLOAD_DURATION = "output_upload_duration"; + // private static UploadNotification uploadNotification = null; @@ -96,6 +98,9 @@ public void release() { } private static int concurrency = 1; private static Semaphore concurrentUploads = new Semaphore(concurrency, true); private static Mutex concurrencyLock = new Mutex(); + private long startUploadTime; + private long endUploadTime; + private long uploadDuration; public UploadTask(@NonNull Context context, @NonNull WorkerParameters workerParams) { @@ -189,6 +194,8 @@ public Result doWork() { return Result.retry(); } + startUploadTime = System.currentTimeMillis(); + // Register me uploadForegroundNotification.progress(getId(), 0f); handleNotification(); @@ -246,6 +253,8 @@ public Result doWork() { return Result.retry(); } } finally { + endUploadTime = System.currentTimeMillis(); + uploadDuration = endUploadTime - startUploadTime; // Always remove ourselves from the notification uploadForegroundNotification.done(getId()); } @@ -254,7 +263,8 @@ public Result doWork() { final Data.Builder outputData = new Data.Builder() .putString(KEY_OUTPUT_ID, id) .putBoolean(KEY_OUTPUT_IS_ERROR, false) - .putInt(KEY_OUTPUT_STATUS_CODE, (!DEBUG_SKIP_UPLOAD) ? response.code() : 200); + .putInt(KEY_OUTPUT_STATUS_CODE, (!DEBUG_SKIP_UPLOAD) ? response.code() : 200) + .putLong(KEY_OUTPUT_UPLOAD_DURATION, uploadDuration); // Try read the response body, if any try {