浏览代码

working on UploadListActivity

Luke Owncloud 10 年之前
父节点
当前提交
2b85ed59b4

+ 2 - 2
res/layout/upload_list_item.xml

@@ -46,7 +46,7 @@
         android:orientation="vertical" >
 
         <TextView
-            android:id="@+id/Filename"
+            android:id="@+id/upload_name"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical"
@@ -66,7 +66,7 @@
             android:weightSum="1">
 
             <TextView
-                android:id="@+id/last_mod"
+                android:id="@+id/upload_status"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="TextView"

+ 117 - 27
src/com/owncloud/android/db/UploadDbHandler.java

@@ -19,14 +19,18 @@ package com.owncloud.android.db;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Observable;
 
 import com.owncloud.android.MainApp;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.operations.UploadFileOperation;
+import com.owncloud.android.ui.adapter.UploadListAdapter;
 
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.database.DatabaseUtils;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 
@@ -37,7 +41,7 @@ import android.database.sqlite.SQLiteOpenHelper;
  * @author LukeOwncloud
  * 
  */
-public class UploadDbHandler {
+public class UploadDbHandler extends Observable {
     private SQLiteDatabase mDB;
     private OpenerHelper mHelper;
     private final String mDatabaseName;
@@ -46,14 +50,15 @@ public class UploadDbHandler {
     static private final String TAG = "UploadDbHandler";
     static private final String TABLE_UPLOAD = "list_of_uploads";
 
+    //for testing only
     public void recreateDb() {
-        mDB.beginTransaction();
-        try {
-            mHelper.onUpgrade(mDB, 0, mDatabaseVersion);
-            mDB.setTransactionSuccessful();
-        } finally {
-            mDB.endTransaction();
-        }
+//        mDB.beginTransaction();
+//        try {
+//            mHelper.onUpgrade(mDB, 0, mDatabaseVersion);
+//            mDB.setTransactionSuccessful();
+//        } finally {
+//            mDB.endTransaction();
+//        }
 
     }
 
@@ -68,14 +73,23 @@ public class UploadDbHandler {
         }
     };
     
-    public UploadDbHandler(Context context) {
+    private UploadDbHandler(Context context) {
         mDatabaseName = MainApp.getDBName();
         mHelper = new OpenerHelper(context);
         mDB = mHelper.getWritableDatabase();
     }
-
+    
+    private static UploadDbHandler me = null;
+    static public UploadDbHandler getInstance(Context context) {
+        if(me == null) {
+            me = new UploadDbHandler(context);            
+        }
+        return me;
+    }
+    
     public void close() {
         mDB.close();
+        me = null;
     }
 
     /**
@@ -162,8 +176,12 @@ public class UploadDbHandler {
 
         @Override
         public void onCreate(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_UPLOAD + " (" + " path TEXT PRIMARY KEY,"
-                    + " uploadObject TEXT);");
+            // PRIMARY KEY should always imply NOT NULL. Unfortunately, due to a
+            // bug in some early versions, this is not the case in SQLite.
+            db.execSQL("CREATE TABLE " + TABLE_UPLOAD + " (" + " path TEXT PRIMARY KEY NOT NULL UNIQUE,"
+                    + " uploadStatus INTEGER NOT NULL, uploadObject TEXT NOT NULL);");
+            // uploadStatus is used to easy filtering, it has precedence over
+            // uploadObject.getUploadStatus()
         }
 
         @Override
@@ -178,43 +196,115 @@ public class UploadDbHandler {
     }
 
     /**
-     * 
+     * Stores an upload object in DB.
      * @param uploadObject
      * @param message
      * @return true on success.
      */
-    public boolean storeUpload(UploadDbObject uploadObject, String message) {
+    public boolean storeUpload(UploadDbObject uploadObject) {
         ContentValues cv = new ContentValues();
         cv.put("path", uploadObject.getLocalPath());
+        cv.put("uploadStatus", uploadObject.getUploadStatus().value);
         cv.put("uploadObject", uploadObject.toString());
         
         long result = mDB.insert(TABLE_UPLOAD, null, cv);
         Log_OC.d(TAG, "putFileForLater returns with: " + result + " for file: " + uploadObject.getLocalPath());
+        if (result == 1) {
+            notifyObserversNow();
+        } else {
+            Log_OC.e(TAG, "Failed to insert item into upload db.");
+        }
         return result != -1;        
     }
+
+
+    /**
+     * Update upload status of file in DB.
+     * 
+     */
+    public void updateUpload(UploadDbObject uploadDbObject) {
+        updateUpload(uploadDbObject.getLocalPath(), uploadDbObject.getUploadStatus(), uploadDbObject.getLastResult());        
+    }
     
+    /**
+     * Update upload status of file.
+     * @param filepath filepath local file path to file. used as identifier.
+     * @param status  new status.
+     * @param result new result of upload operation 
+     * @return 1 if file status was updated, else 0.
+     */
+    public int updateUpload(String filepath, UploadStatus status, RemoteOperationResult result) {
+        Cursor c = mDB.query(TABLE_UPLOAD, null, "path=?", new String[] {filepath}, null, null, null);
+        if(c.getCount() != 1) {
+            Log_OC.e(TAG, c.getCount() + " items for path=" + filepath + " available in UploadDb. Expected 1." );
+            return 0;
+        }
+        if (c.moveToFirst()) {
+            //read upload object and update
+            String uploadObjectString = c.getString(c.getColumnIndex("uploadObject"));
+            UploadDbObject uploadObject = UploadDbObject.fromString(uploadObjectString);            
+            uploadObject.setLastResult(result);
+            uploadObject.setUploadStatus(status);
+            uploadObjectString = uploadObject.toString();
+            //store update upload object to db
+            ContentValues cv = new ContentValues();
+            cv.put("uploadStatus", status.value);
+            cv.put("uploadObject", uploadObjectString);
+            int r = mDB.update(TABLE_UPLOAD, cv, "path=?", new String[] { filepath });
+            if (r == 1) {
+                notifyObserversNow();
+            } else {
+                Log_OC.e(TAG, "Failed to update upload db.");
+            }
+            return r;
+        }
+        return 0;
+    }
+    
+    /**
+     * Should be called when some value of this DB was changed. All observers are informed.
+     */
+    public void notifyObserversNow() {
+        Log_OC.d("UploadListAdapter", "notifyObserversNow");
+        setChanged();
+        notifyObservers();
+    }
+    
+    /**
+     * Remove upload from upload list. Should be called when cleaning up upload list. 
+     * @param localPath
+     * @return true when one or more upload entries were removed
+     */
     public boolean removeUpload(String localPath) {
         long result = mDB.delete(TABLE_UPLOAD, "path = ?", new String[] { localPath });
         Log_OC.d(TABLE_UPLOAD, "delete returns with: " + result + " for file: " + localPath);
         return result != 0;
-
     }
-    
+
     public List<UploadDbObject> getAllStoredUploads() {
-        Cursor c = mDB.query(TABLE_UPLOAD, null, null, null, null, null, null);
+        return getUploads(null, null);
+    }
+
+    private List<UploadDbObject> getUploads(String selection, String[] selectionArgs) {
+        Cursor c = mDB.query(TABLE_UPLOAD, null, selection, selectionArgs, null, null, null);
         List<UploadDbObject> list = new ArrayList<UploadDbObject>();
         if (c.moveToFirst()) {
-          do {
-              String file_path = c.getString(c.getColumnIndex("path"));
-              String uploadObjectString = c.getString(c.getColumnIndex("uploadObject"));
-              UploadDbObject uploadObject = UploadDbObject.fromString(uploadObjectString);
-              if(uploadObject == null) {
-                  Log_OC.e(TAG, "Could not deserialize UploadDbObject " + uploadObjectString);
-              } else {
-                  list.add(uploadObject);
-              }
-          } while (c.moveToNext());
+            do {
+                String uploadObjectString = c.getString(c.getColumnIndex("uploadObject"));
+                UploadDbObject uploadObject = UploadDbObject.fromString(uploadObjectString);
+                if (uploadObject == null) {
+                    Log_OC.e(TAG, "Could not deserialize UploadDbObject " + uploadObjectString);
+                } else {
+                    list.add(uploadObject);
+                }
+            } while (c.moveToNext());
         }
         return list;
     }
+
+    public List<UploadDbObject> getAllPendingUploads() {
+        return getUploads("uploadStatus!=" + UploadStatus.UPLOAD_SUCCEEDED.value, null);
+    }
+
+    
 }

+ 1 - 1
src/com/owncloud/android/db/UploadDbObject.java

@@ -17,7 +17,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 
 /**
- * Stores all information in order to start upload. PersistentUploadObject can
+ * Stores all information in order to start upload operations. PersistentUploadObject can
  * be stored persistently by {@link UploadDbHandler}.
  * 
  * @author LukeOwncloud

+ 82 - 42
src/com/owncloud/android/files/services/FileUploadService.java

@@ -26,6 +26,8 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -59,6 +61,7 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.db.UploadDbHandler;
 import com.owncloud.android.db.UploadDbHandler.UploadStatus;
 import com.owncloud.android.db.UploadDbObject;
+import com.owncloud.android.files.InstantUploadBroadcastReceiver;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
@@ -176,8 +179,7 @@ public class FileUploadService extends Service {
      * is being uploaded to {@link UploadFileOperation}.
      */
     private ConcurrentMap<String, UploadFileOperation> mActiveUploads = new ConcurrentHashMap<String, UploadFileOperation>();
-    private UploadFileOperation mCurrentUpload = null;
-
+    
     private NotificationManager mNotificationManager;
     private NotificationCompat.Builder mNotificationBuilder;
 
@@ -227,16 +229,19 @@ public class FileUploadService extends Service {
         mBinder = new FileUploaderBinder();
         mConnectivityChangeReceiver = new ConnectivityChangeReceiver();
         registerReceiver(mConnectivityChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
-        mDb = new UploadDbHandler(this.getBaseContext());
-//        mDb.recreateDb(); //for testing only
+        mDb = UploadDbHandler.getInstance(this.getBaseContext());
+        mDb.recreateDb(); //for testing only
     }
 
     public class ConnectivityChangeReceiver extends BroadcastReceiver {
 
         @Override
         public void onReceive(Context arg0, Intent arg1) {
-            // upload pending wifi only files.
-            onStartCommand(null, 0, 0);
+            if(InstantUploadBroadcastReceiver.isOnline(getApplicationContext()))
+            {
+                // upload pending wifi only files.
+                onStartCommand(null, 0, 0);
+            }
         }
 
     }
@@ -271,7 +276,12 @@ public class FileUploadService extends Service {
             // service) or connectivity change was detected. ==> check persistent upload
             // list.
             //
-            List<UploadDbObject> list = mDb.getAllStoredUploads();
+            List<UploadDbObject> list = mDb.getAllPendingUploads();
+            for (UploadDbObject uploadDbObject : list) {
+                uploadDbObject.setUploadStatus(UploadStatus.UPLOAD_LATER);
+                uploadDbObject.setLastResult(null);
+                mDb.updateUpload(uploadDbObject);
+            }
             requestedUploads.addAll(list);
         } else {
 
@@ -355,7 +365,7 @@ public class FileUploadService extends Service {
                 uploadObject.setLocalAction(localAction);
                 uploadObject.setUseWifiOnly(isUseWifiOnly);
                 uploadObject.setUploadStatus(UploadStatus.UPLOAD_LATER);
-                boolean success = mDb.storeUpload(uploadObject, "upload at " + new Date());
+                boolean success = mDb.storeUpload(uploadObject);
                 if(!success) {
                     Log_OC.e(TAG, "Could not add upload to database.");
                 }
@@ -500,11 +510,25 @@ public class FileUploadService extends Service {
 
         @Override
         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
-                String fileName) {
-            String key = buildRemoteName(mCurrentUpload.getAccount(), mCurrentUpload.getFile());
+                String localFileName) {
+            Set<Entry<String, UploadFileOperation>> uploads = mActiveUploads.entrySet();
+            UploadFileOperation currentUpload = null;
+            //unfortunately we do not have the remote upload path here, so search through all uploads.
+            //however, this may lead to problems, if user uploads same file twice to different destinations.
+            //this can only be fixed by replacing localFileName with remote path.
+            for (Entry<String, UploadFileOperation> entry : uploads) {
+                if(entry.getValue().getStoragePath().equals(localFileName)) {
+                    if(currentUpload != null) {
+                        Log_OC.e(TAG, "Found two current uploads with same remote path. Ignore.");
+                        return;
+                    }
+                    currentUpload = entry.getValue();
+                }
+            }
+            String key = buildRemoteName(currentUpload.getAccount(), currentUpload.getFile());
             OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
             if (boundListener != null) {
-                boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
+                boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, localFileName);
             }
         }
 
@@ -536,7 +560,8 @@ public class FileUploadService extends Service {
             if (msg.obj != null) {
                 Iterator<UploadDbObject> it = requestedUploads.iterator();
                 while (it.hasNext()) {
-                    mService.uploadFile(it.next());
+                    UploadDbObject uploadObject = it.next();
+                    mService.uploadFile(uploadObject);
                 }
             }
             mService.stopSelf(msg.arg1);
@@ -544,13 +569,19 @@ public class FileUploadService extends Service {
     }
 
     /**
-     * Core upload method: sends the file(s) to upload
+     * Core upload method: sends the file(s) to upload. This function blocks until upload succeeded or failed.
      * 
      * @param uploadDbObject Key to access the upload to perform, contained in
      *            mPendingUploads
      */
     private void uploadFile(UploadDbObject uploadDbObject) {
+        
+        if(uploadDbObject.getUploadStatus() == UploadStatus.UPLOAD_SUCCEEDED) {
+            Log_OC.w(TAG, "Already succeeded uploadObject was again scheduled for upload. Fix that!");
+            return;
+        }
 
+        UploadFileOperation currentUpload = null;
         synchronized (mActiveUploads) {
             //How does this work? Is it thread-safe to set mCurrentUpload here?
             //What happens if other mCurrentUpload is currently in progress?
@@ -558,10 +589,16 @@ public class FileUploadService extends Service {
             //It seems that upload does work, however the upload state is not set
             //back of the first upload when a second upload starts while first is
             //in progress (yellow up-arrow does not disappear of first upload)
-            mCurrentUpload = mActiveUploads.get(uploadDbObject.getRemotePath());
+            currentUpload = mActiveUploads.get(uploadDbObject.getRemotePath());
             
             //if upload not in progress, start it now
-            if(mCurrentUpload == null) {
+            if(currentUpload == null) {
+                if (uploadDbObject.isUseWifiOnly()
+                        && !InstantUploadBroadcastReceiver.isConnectedViaWiFi(getApplicationContext())) {
+                    Log_OC.d(TAG, "Do not start upload because it is wifi-only.");
+                    return;
+                }
+                
                 AccountManager aMgr = AccountManager.get(this);
                 Account account = uploadDbObject.getAccount(getApplicationContext());
                 String version = aMgr.getUserData(account, Constants.KEY_OC_VERSION);
@@ -573,30 +610,29 @@ public class FileUploadService extends Service {
                 uploadKey = buildRemoteName(account, uploadDbObject.getRemotePath());
                 OCFile file = obtainNewOCFileToUpload(uploadDbObject.getRemotePath(), uploadDbObject.getLocalPath(),
                         uploadDbObject.getMimeType());
-                mCurrentUpload = new UploadFileOperation(account, file, chunked, uploadDbObject.isForceOverwrite(),
+                currentUpload = new UploadFileOperation(account, file, chunked, uploadDbObject.isForceOverwrite(),
                         uploadDbObject.getLocalAction(), getApplicationContext());
                 if (uploadDbObject.isCreateRemoteFolder()) {
-                    mCurrentUpload.setRemoteFolderToBeCreated();
+                    currentUpload.setRemoteFolderToBeCreated();
                 }
-                mActiveUploads.putIfAbsent(uploadKey, mCurrentUpload); // Grants that
+                mActiveUploads.putIfAbsent(uploadKey, currentUpload); // Grants that
                 // the file only upload once time
 
-                mCurrentUpload.addDatatransferProgressListener((FileUploaderBinder) mBinder);
+                currentUpload.addDatatransferProgressListener((FileUploaderBinder) mBinder);
             }
             
         }
 
-        if (mCurrentUpload != null) {
+        if (currentUpload != null) {
 
-            notifyUploadStart(mCurrentUpload);
+            notifyUploadStart(currentUpload);
 
             RemoteOperationResult uploadResult = null, grantResult = null;
-            UploadFileOperation justFinishedUpload;
             try {
                 // / prepare client object to send requests to the ownCloud
                 // server
-                if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
-                    mLastAccount = mCurrentUpload.getAccount();
+                if (mUploadClient == null || !mLastAccount.equals(currentUpload.getAccount())) {
+                    mLastAccount = currentUpload.getAccount();
                     mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
                     OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
                     mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, this);
@@ -604,18 +640,18 @@ public class FileUploadService extends Service {
 
                 // / check the existence of the parent folder for the file to
                 // upload
-                String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent();
+                String remoteParentPath = new File(currentUpload.getRemotePath()).getParent();
                 remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ? remoteParentPath
                         : remoteParentPath + OCFile.PATH_SEPARATOR;
-                grantResult = grantFolderExistence(remoteParentPath);
+                grantResult = grantFolderExistence(currentUpload, remoteParentPath);
 
                 // / perform the upload
                 if (grantResult.isSuccess()) {
                     OCFile parent = mStorageManager.getFileByPath(remoteParentPath);
-                    mCurrentUpload.getFile().setParentId(parent.getFileId());
-                    uploadResult = mCurrentUpload.execute(mUploadClient);
+                    currentUpload.getFile().setParentId(parent.getFileId());
+                    uploadResult = currentUpload.execute(mUploadClient);
                     if (uploadResult.isSuccess()) {
-                        saveUploadedFile();
+                        saveUploadedFile(currentUpload);
                     }
                 } else {
                     uploadResult = grantResult;
@@ -644,8 +680,8 @@ public class FileUploadService extends Service {
             }
 
             // notify result
-            notifyUploadResult(uploadResult, mCurrentUpload);
-            sendFinalBroadcast(mCurrentUpload, uploadResult);            
+            notifyUploadResult(uploadResult, currentUpload);
+            sendFinalBroadcast(currentUpload, uploadResult);            
 
         }
 
@@ -662,11 +698,11 @@ public class FileUploadService extends Service {
      * @return An {@link OCFile} instance corresponding to the folder where the
      *         file will be uploaded.
      */
-    private RemoteOperationResult grantFolderExistence(String pathToGrant) {
+    private RemoteOperationResult grantFolderExistence(UploadFileOperation currentUpload, String pathToGrant) {
         RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, this, false);
         RemoteOperationResult result = operation.execute(mUploadClient);
         if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND
-                && mCurrentUpload.isRemoteFolderToBeCreated()) {
+                && currentUpload.isRemoteFolderToBeCreated()) {
             SyncOperation syncOp = new CreateFolderOperation(pathToGrant, true);
             result = syncOp.execute(mUploadClient, mStorageManager);
         }
@@ -710,8 +746,8 @@ public class FileUploadService extends Service {
      * 
      * TODO refactor this ugly thing
      */
-    private void saveUploadedFile() {
-        OCFile file = mCurrentUpload.getFile();
+    private void saveUploadedFile(UploadFileOperation currentUpload) {
+        OCFile file = currentUpload.getFile();
         if (file.fileExists()) {
             file = mStorageManager.getFileById(file.getFileId());
         }
@@ -720,7 +756,7 @@ public class FileUploadService extends Service {
 
         // new PROPFIND to keep data consistent with server
         // in theory, should return the same we already have
-        ReadRemoteFileOperation operation = new ReadRemoteFileOperation(mCurrentUpload.getRemotePath());
+        ReadRemoteFileOperation operation = new ReadRemoteFileOperation(currentUpload.getRemotePath());
         RemoteOperationResult result = operation.execute(mUploadClient);
         if (result.isSuccess()) {
             updateOCFile(file, (RemoteFile) result.getData().get(0));
@@ -729,8 +765,8 @@ public class FileUploadService extends Service {
 
         // / maybe this would be better as part of UploadFileOperation... or
         // maybe all this method
-        if (mCurrentUpload.wasRenamed()) {
-            OCFile oldFile = mCurrentUpload.getOldFile();
+        if (currentUpload.wasRenamed()) {
+            OCFile oldFile = currentUpload.getOldFile();
             if (oldFile.fileExists()) {
                 oldFile.setStoragePath(null);
                 mStorageManager.saveFile(oldFile);
@@ -811,6 +847,8 @@ public class FileUploadService extends Service {
                 showDetailsIntent, 0));
 
         mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotificationBuilder.build());
+        
+        mDb.updateUpload(upload.getOriginalStoragePath(), UploadStatus.UPLOAD_IN_PROGRESS, null);
     }
 
     /**
@@ -857,10 +895,10 @@ public class FileUploadService extends Service {
                 mUploadClient = null;
                 // grant that future retries on the same account will get the
                 // fresh credentials
+                
             } else {
                 mNotificationBuilder.setContentText(content);
 
-
                 try {
                     String message = uploadResult.getLogMessage() + " errorCode: " + uploadResult.getCode();
                     Log_OC.e(TAG, message + " Http-Code: " + uploadResult.getHttpCode());
@@ -886,14 +924,16 @@ public class FileUploadService extends Service {
 
             if (uploadResult.isSuccess()) {
 
-               //TODO just edit state of upload. do not delete here.
-               mDb.removeUpload(mCurrentUpload.getOriginalStoragePath());
+               mDb.updateUpload(upload.getOriginalStoragePath(), UploadStatus.UPLOAD_SUCCEEDED, uploadResult);
                
                 // remove success notification, with a delay of 2 seconds
                 NotificationDelayer.cancelWithDelay(mNotificationManager, R.string.uploader_upload_succeeded_ticker,
                         2000);
-
+            } else {
+                mDb.updateUpload(upload.getOriginalStoragePath(), UploadStatus.UPLOAD_FAILED, uploadResult);
             }
+        } else {
+            mDb.updateUpload(upload.getOriginalStoragePath(), UploadStatus.UPLOAD_FAILED, uploadResult);
         }
     }
 

+ 1 - 1
src/com/owncloud/android/ui/activity/Preferences.java

@@ -81,7 +81,7 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mDbHandler = new UploadDbHandler(getBaseContext());
+        mDbHandler = UploadDbHandler.getInstance(getBaseContext());
         addPreferencesFromResource(R.xml.preferences);
 
         ActionBar actionBar = getSherlock().getActionBar();

+ 3 - 0
src/com/owncloud/android/ui/activity/UploadListActivity.java

@@ -13,6 +13,9 @@ import com.owncloud.android.ui.fragment.UploadListFragment;
  * Activity listing pending, active, and completed uploads. User can delete
  * completed uploads from view. Content of this list of coming from
  * {@link UploadDbHandler}.
+ * 
+ * @author LukeOwncloud
+ *
  */
 public class UploadListActivity extends FileActivity implements UploadListFragment.ContainerActivity {
 

+ 108 - 57
src/com/owncloud/android/ui/adapter/UploadListAdapter.java

@@ -5,8 +5,12 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
 
+import android.app.Activity;
 import android.content.Context;
+import android.database.DataSetObserver;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -19,23 +23,44 @@ import android.widget.TextView;
 import com.owncloud.android.R;
 import com.owncloud.android.db.UploadDbHandler;
 import com.owncloud.android.db.UploadDbObject;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.activity.UploadListActivity;
 import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.FileStorageUtils;
 
 /**
- * This Adapter populates a ListView with following types of uploads: pending, active, completed.
- * Filtering possible.
+ * This Adapter populates a ListView with following types of uploads: pending,
+ * active, completed. Filtering possible.
  * 
  */
-public class UploadListAdapter extends BaseAdapter implements ListAdapter {
-    
-    private Context mContext;
+public class UploadListAdapter extends BaseAdapter implements ListAdapter, Observer {
+
+    private static final String TAG = "UploadListAdapter";
+    private Activity mActivity;
     private UploadDbObject[] mUploads = null;
+    UploadDbHandler mDb;
 
-    public UploadListAdapter(Context context) {
-        mContext = context;
+    public UploadListAdapter(Activity context) {
+        Log_OC.d(TAG, "UploadListAdapter");
+        mActivity = context;
+        mDb = UploadDbHandler.getInstance(mActivity);
         loadUploadItemsFromDb();
     }
 
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        super.registerDataSetObserver(observer);
+        mDb.addObserver(this);
+        Log_OC.d(TAG, "registerDataSetObserver");
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        super.unregisterDataSetObserver(observer);
+        mDb.deleteObserver(this);
+        Log_OC.d(TAG, "unregisterDataSetObserver");
+    }
+
     @Override
     public boolean areAllItemsEnabled() {
         return true;
@@ -72,53 +97,67 @@ public class UploadListAdapter extends BaseAdapter implements ListAdapter {
     public View getView(int position, View convertView, ViewGroup parent) {
         View view = convertView;
         if (view == null) {
-            LayoutInflater inflator = (LayoutInflater) mContext
-                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            LayoutInflater inflator = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             view = inflator.inflate(R.layout.upload_list_item, null);
         }
         if (mUploads != null && mUploads.length > position) {
-            UploadDbObject file = mUploads[position];
-            
-            TextView fileName = (TextView) view.findViewById(R.id.Filename);
-            String name = file.getLocalPath();
+            UploadDbObject uploadObject = mUploads[position];
+
+            TextView fileName = (TextView) view.findViewById(R.id.upload_name);
+            String name = FileStorageUtils.removeDataFolderPath(uploadObject.getLocalPath());
             fileName.setText(name);
-            
-//            ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);
-//            if (!file.isDirectory()) {
-//                fileIcon.setImageResource(R.drawable.file);
-//            } else {
-//                fileIcon.setImageResource(R.drawable.ic_menu_archive);
-//            }
+
+            TextView statusView = (TextView) view.findViewById(R.id.upload_status);
+            String status = uploadObject.getUploadStatus().toString();
+            if (uploadObject.getLastResult() != null && !uploadObject.getLastResult().isSuccess()) {
+                status += ": " + uploadObject.getLastResult().getLogMessage();
+            }
+            statusView.setText(status);
+
+            // ImageView fileIcon = (ImageView)
+            // view.findViewById(R.id.imageView1);
+            // if (!file.isDirectory()) {
+            // fileIcon.setImageResource(R.drawable.file);
+            // } else {
+            // fileIcon.setImageResource(R.drawable.ic_menu_archive);
+            // }
 
             TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);
-            TextView lastModV = (TextView) view.findViewById(R.id.last_mod);
             ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);
-//            if (!file.isDirectory()) {
-//                fileSizeV.setVisibility(View.VISIBLE);
-//                fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.length()));
-//                lastModV.setVisibility(View.VISIBLE);
-//                lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.lastModified()));
-//                ListView parentList = (ListView)parent;
-//                if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) { 
-//                    checkBoxV.setVisibility(View.GONE);
-//                } else {
-//                    if (parentList.isItemChecked(position)) {
-//                        checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);
-//                    } else {
-//                        checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);
-//                    }
-//                    checkBoxV.setVisibility(View.VISIBLE);
-//                }
-//
-//            } else {
-                fileSizeV.setVisibility(View.GONE);
-                lastModV.setVisibility(View.GONE);
-                checkBoxV.setVisibility(View.GONE);
-//            }
-            
-            view.findViewById(R.id.imageView2).setVisibility(View.INVISIBLE);   // not GONE; the alignment changes; ugly way to keep it
+            // if (!file.isDirectory()) {
+            // fileSizeV.setVisibility(View.VISIBLE);
+            // fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.length()));
+            // lastModV.setVisibility(View.VISIBLE);
+            // lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.lastModified()));
+            // ListView parentList = (ListView)parent;
+            // if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
+            // checkBoxV.setVisibility(View.GONE);
+            // } else {
+            // if (parentList.isItemChecked(position)) {
+            // checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);
+            // } else {
+            // checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);
+            // }
+            // checkBoxV.setVisibility(View.VISIBLE);
+            // }
+            //
+            // } else {
+            fileSizeV.setVisibility(View.GONE);
+            checkBoxV.setVisibility(View.GONE);
+            // }
+
+            view.findViewById(R.id.imageView2).setVisibility(View.INVISIBLE); // not
+                                                                              // GONE;
+                                                                              // the
+                                                                              // alignment
+                                                                              // changes;
+                                                                              // ugly
+                                                                              // way
+                                                                              // to
+                                                                              // keep
+                                                                              // it
             view.findViewById(R.id.imageView3).setVisibility(View.GONE);
-            
+
             view.findViewById(R.id.sharedIcon).setVisibility(View.GONE);
             view.findViewById(R.id.sharedWithMeIcon).setVisibility(View.GONE);
         }
@@ -144,28 +183,40 @@ public class UploadListAdapter extends BaseAdapter implements ListAdapter {
     /**
      * Load upload items from {@link UploadDbHandler}.
      */
-    public void loadUploadItemsFromDb() {
-        UploadDbHandler mDb = new UploadDbHandler(mContext);
+    private void loadUploadItemsFromDb() {
+        Log_OC.d(TAG, "loadUploadItemsFromDb");
         List<UploadDbObject> list = mDb.getAllStoredUploads();
         mUploads = list.toArray(new UploadDbObject[list.size()]);
         if (mUploads != null) {
             Arrays.sort(mUploads, new Comparator<UploadDbObject>() {
                 @Override
                 public int compare(UploadDbObject lhs, UploadDbObject rhs) {
-//                    if (lhs.isDirectory() && !rhs.isDirectory()) {
-//                        return -1;
-//                    } else if (!lhs.isDirectory() && rhs.isDirectory()) {
-//                        return 1;
-//                    }
+                    // if (lhs.isDirectory() && !rhs.isDirectory()) {
+                    // return -1;
+                    // } else if (!lhs.isDirectory() && rhs.isDirectory()) {
+                    // return 1;
+                    // }
                     return compareNames(lhs, rhs);
                 }
-            
+
                 private int compareNames(UploadDbObject lhs, UploadDbObject rhs) {
-                    return lhs.getLocalPath().toLowerCase().compareTo(rhs.getLocalPath().toLowerCase());                
+                    return lhs.getLocalPath().toLowerCase().compareTo(rhs.getLocalPath().toLowerCase());
                 }
-            
+
             });
         }
-        notifyDataSetChanged();
+        mActivity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                notifyDataSetChanged();
+            }
+        });
+
+    }
+
+    @Override
+    public void update(Observable arg0, Object arg1) {
+        Log_OC.d(TAG, "update");
+        loadUploadItemsFromDb();
     }
 }

+ 1 - 2
src/com/owncloud/android/ui/fragment/UploadListFragment.java

@@ -92,9 +92,8 @@ public class UploadListFragment extends ExtendedListFragment {
         mAdapter = new UploadListAdapter(getActivity());
         setListAdapter(mAdapter);
 
-        Log_OC.i(TAG, "onActivityCreated() stop");
     }
-
+    
     public void selectAll() {
         int numberOfFiles = mAdapter.getCount();
         for (int i = 0; i < numberOfFiles; i++) {

+ 13 - 0
src/com/owncloud/android/utils/FileStorageUtils.java

@@ -41,6 +41,19 @@ import android.os.StatFs;
 public class FileStorageUtils {
     //private static final String LOG_TAG = "FileStorageUtils";
 
+    /**
+     * Takes a full path to owncloud file and removes beginning which is path to ownload data folder.
+     * If fullPath does not start with that folder, fullPath is returned as is.
+     */
+    public static final String removeDataFolderPath(String fullPath) {
+        File sdCard = Environment.getExternalStorageDirectory();
+        String dataFolderPath = sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/";
+        if(fullPath.indexOf(dataFolderPath) == 0) {
+            return fullPath.substring(dataFolderPath.length());
+        }
+        return fullPath;
+    }
+    
     /**
      * Get local owncloud storage path for accountName.
      */