Merge of master after sync_review was merged into it
authorDavid A. Velasco <dvelasco@solidgear.es>
Fri, 23 Nov 2012 09:25:06 +0000 (10:25 +0100)
committerDavid A. Velasco <dvelasco@solidgear.es>
Fri, 23 Nov 2012 09:25:06 +0000 (10:25 +0100)
1  2 
res/values/strings.xml
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/operations/RenameFileOperation.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

      <string name="uploader_upload_failed_content_multiple">Upload failed: %1$d/%2$d files were upload</string>
      <string name="downloader_download_in_progress_ticker">Downloading &#8230;</string>
      <string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
--    <string name="downloader_download_succeeded_ticker">Download suceeded</string>
++    <string name="downloader_download_succeeded_ticker">Download succeeded</string>
      <string name="downloader_download_succeeded_content">%1$s was successfully download</string>
      <string name="downloader_download_failed_ticker">Download failed</string>
      <string name="downloader_download_failed_content">Download of %1$s could not be completed</string>
@@@ -118,16 -118,13 +118,18 @@@ public class FileDataStorageManager imp
          if (!file.isDirectory())
              cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
          cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
-         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDate());
+         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
+         cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
          cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
  
--        if (fileExists(file.getRemotePath())) {
--            OCFile oldFile = getFileByPath(file.getRemotePath());
-             if (file.getStoragePath() == null && oldFile.getStoragePath() != null)
-                 file.setStoragePath(oldFile.getStoragePath());
-             if (!file.isDirectory());
-                 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
--            file.setFileId(oldFile.getFileId());
++        boolean sameRemotePath = fileExists(file.getRemotePath());
++        if (sameRemotePath ||
++            fileExists(file.getFileId())        ) {           // for renamed files; no more delete and create
++            
++            if (sameRemotePath) {
++                OCFile oldFile = getFileByPath(file.getRemotePath());
++                file.setFileId(oldFile.getFileId());
++            }
  
              overriden = true;
              if (getContentResolver() != null) {
          if (file.isDown() && removeLocalCopy) {
              new File(file.getStoragePath()).delete();
          }
-             File f = new File(FileDownloader.getSavePath(mAccount.name) + file.getRemotePath());
 +        if (file.isDirectory() && removeLocalCopy) {
-             String defaultSavePath = FileDownloader.getSavePath(mAccount.name);
++            File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
 +            if (f.exists() && f.isDirectory() && (f.list() == null || f.list().length == 0)) {
 +                f.delete();
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent) {
 +        // TODO consider possible failures
 +        if (dir != null && dir.isDirectory() && dir.getFileId() != -1) {
 +            Vector<OCFile> children = getDirectoryContent(dir);
 +            if (children != null) {
 +                OCFile child = null;
 +                for (int i=0; i<children.size(); i++) {
 +                    child = children.get(i);
 +                    if (child.isDirectory()) {
 +                        removeDirectory(child, removeDBData, removeLocalContent);
 +                    } else {
 +                        if (removeDBData) {
 +                            removeFile(child, removeLocalContent);
 +                        } else if (removeLocalContent) {
 +                            if (child.isDown()) {
 +                                new File(child.getStoragePath()).delete();
 +                            }
 +                        }
 +                    }
 +                }
 +                if (removeDBData) {
 +                    removeFile(dir, true);
 +                }
 +            }
 +        }
 +    }
 +    
 +    
 +    /**
 +     * Updates database for a folder that was moved to a different location.
 +     * 
 +     * TODO explore better (faster) implementations
 +     * TODO throw exceptions up !
 +     */
 +    @Override
 +    public void moveDirectory(OCFile dir, String newPath) {
 +        // TODO check newPath
 +        
 +        if (dir != null && dir.isDirectory() && dir.fileExists() && !dir.getFileName().equals(OCFile.PATH_SEPARATOR)) {
 +            /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir')
 +            Cursor c = null;
 +            if (getContentProvider() != null) {
 +                try {
 +                    c = getContentProvider().query(ProviderTableMeta.CONTENT_URI, 
 +                                                    null,
 +                                                    ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
 +                                                    new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
 +                } catch (RemoteException e) {
 +                    Log.e(TAG, e.getMessage());
 +                }
 +            } else {
 +                c = getContentResolver().query(ProviderTableMeta.CONTENT_URI, 
 +                                                null,
 +                                                ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
 +                                                new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
 +            }
 +
 +            /// 2. prepare a batch of update operations to change all the descendants
 +            ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(c.getCount());
 +            int lengthOfOldPath = dir.getRemotePath().length();
++            String defaultSavePath = FileStorageUtils.getSavePath(mAccount.name);
 +            int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
 +            if (c.moveToFirst()) {
 +                do {
 +                    ContentValues cv = new ContentValues(); // don't take the constructor out of the loop and clear the object
 +                    OCFile child = createFileInstance(c);
 +                    cv.put(ProviderTableMeta.FILE_PATH, newPath + child.getRemotePath().substring(lengthOfOldPath));
 +                    if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
 +                        cv.put(ProviderTableMeta.FILE_STORAGE_PATH, defaultSavePath + newPath + child.getStoragePath().substring(lengthOfOldStoragePath));
 +                    }
 +                    operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
 +                                                                        withValues(cv).
 +                                                                        withSelection(  ProviderTableMeta._ID + "=?", 
 +                                                                                new String[] { String.valueOf(child.getFileId()) })
 +                                                                                .build());
 +                } while (c.moveToNext());
 +            }
 +            c.close();
 +            
 +            /// 3. apply updates in batch
 +            try {
 +                if (getContentResolver() != null) {
 +                    getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
 +                
 +                } else {
 +                    getContentProvider().applyBatch(operations);
 +                }
 +                
 +            } catch (OperationApplicationException e) {
 +                Log.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e);
 +                
 +            } catch (RemoteException e) {
 +                Log.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e);
 +            }
 +            
 +        }
      }
  
  }
@@@ -64,17 -71,22 +71,21 @@@ import eu.alefzero.webdav.WebdavClient
  public class FileUploader extends Service implements OnDatatransferProgressListener {
  
      public static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH";
 -    public static final String EXTRA_PARENT_DIR_ID = "PARENT_DIR_ID";
      public static final String EXTRA_UPLOAD_RESULT = "RESULT";
      public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
+     public static final String EXTRA_OLD_REMOTE_PATH = "OLD_REMOTE_PATH";
      public static final String EXTRA_FILE_PATH = "FILE_PATH";
+     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";    
      
 -    public static final String KEY_LOCAL_FILE = "LOCAL_FILE";       // TODO remove this as a possible input argument ; use KEY_FILE everywhere
 -    public static final String KEY_REMOTE_FILE = "REMOTE_FILE";     // TODO remove this as a possible input argument ; use KEY_FILE everywhere
+     public static final String KEY_FILE = "FILE";
 +    public static final String KEY_LOCAL_FILE = "LOCAL_FILE";
 +    public static final String KEY_REMOTE_FILE = "REMOTE_FILE";
+     public static final String KEY_MIME_TYPE = "MIME_TYPE";
      public static final String KEY_ACCOUNT = "ACCOUNT";
+     
      public static final String KEY_UPLOAD_TYPE = "UPLOAD_TYPE";
      public static final String KEY_FORCE_OVERWRITE = "KEY_FORCE_OVERWRITE";
-     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";    
-     public static final String KEY_MIME_TYPE = "MIME_TYPE";
      public static final String KEY_INSTANT_UPLOAD = "INSTANT_UPLOAD";
  
      public static final int UPLOAD_SINGLE_FILE = 0;
          end.putExtra(EXTRA_FILE_PATH, upload.getStoragePath());
          end.putExtra(ACCOUNT_NAME, upload.getAccount().name);
          end.putExtra(EXTRA_UPLOAD_RESULT, uploadResult.isSuccess());
-         sendBroadcast(end);
 -        end.putExtra(EXTRA_PARENT_DIR_ID, upload.getFile().getParentId());
+         sendStickyBroadcast(end);
      }
  
  
@@@ -152,35 -143,6 +152,35 @@@ public class RenameFileOperation extend
      }
  
      
-         String localPath = FileDownloader.getSavePath(mAccount.name) + mFile.getRemotePath();
 +    private void saveLocalDirectory() {
 +        mStorageManager.moveDirectory(mFile, mNewRemotePath);
-             localDir.renameTo(new File(FileDownloader.getSavePath(mAccount.name) + mNewRemotePath));
++        String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
 +        File localDir = new File(localPath);
 +        if (localDir.exists()) {
++            localDir.renameTo(new File(FileStorageUtils.getSavePath(mAccount.name) + mNewRemotePath));
 +            // TODO - if renameTo fails, children files that are already down will result unlinked
 +        }
 +    }
 +
 +    private void saveLocalFile() {
 +        mFile.setFileName(mNewName);
 +        
 +        // try to rename the local copy of the file
 +        if (mFile.isDown()) {
 +            File f = new File(mFile.getStoragePath());
 +            String parentStoragePath = f.getParent();
 +            if (!parentStoragePath.endsWith(File.separator))
 +                parentStoragePath += File.separator;
 +            if (f.renameTo(new File(parentStoragePath + mNewName))) {
 +                mFile.setStoragePath(parentStoragePath + mNewName);
 +            }
 +            // else - NOTHING: the link to the local file is kept although the local name can't be updated
 +            // TODO - study conditions when this could be a problem
 +        }
 +        
 +        mStorageManager.saveFile(mFile);
 +    }
 +
      /**
       * Checks if the new name to set is valid in the file system 
       * 
      }
  
  
 -    /**
 -     * Creates a new OCFile for the new remote name of the renamed file.
 -     * 
 -     * @return      OCFile object with the same information than mFile, but the renamed remoteFile and the storagePath (empty)
 -     */
 -    private OCFile obtainUpdatedFile() {
 -        OCFile file = new OCFile(mStorageManager.getFileById(mFile.getParentId()).getRemotePath() + mNewName);
 -        file.setCreationTimestamp(mFile.getCreationTimestamp());
 -        file.setFileId(mFile.getFileId());
 -        file.setFileLength(mFile.getFileLength());
 -        file.setKeepInSync(mFile.keepInSync());
 -        file.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
 -        file.setLastSyncDateForData(mFile.getLastSyncDateForData());
 -        file.setMimetype(mFile.getMimetype());
 -        file.setModificationTimestamp(mFile.getModificationTimestamp());
 -        file.setParentId(mFile.getParentId());
 -        return file;
 -    }
 -
--
--    // move operation - TODO: find out why org.apache.jackrabbit.webdav.client.methods.MoveMethod is not used instead ¿?
++    // move operation
      private class LocalMoveMethod extends DavMethodBase {
  
          public LocalMoveMethod(String uri, String dest) {
@@@ -257,7 -274,7 +274,6 @@@ public class FileDetailFragment extend
      public void onClick(View v) {\r
          switch (v.getId()) {\r
              case R.id.fdDownloadBtn: {\r
--                //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath())) {\r
                  FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
                  FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
                  if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
       */\r
      public void updateFileDetails(OCFile file, Account ocAccount) {\r
          mFile = file;\r
+         if (ocAccount != null && ( \r
+                 mStorageManager == null || \r
+                 (mAccount != null && !mAccount.equals(ocAccount))\r
+            )) {\r
+             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());\r
+         }\r
          mAccount = ocAccount;\r
 -        updateFileDetails();\r
 +        updateFileDetails(false);\r
      }\r
      \r
  \r
      private void setButtonsForDown() {\r
          if (!isEmpty()) {\r
              Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-             downloadButton.setText(R.string.filedetails_redownload);\r
-             //downloadButton.setEnabled(true);\r
+             downloadButton.setText(R.string.filedetails_sync_file);\r
 -            //downloadButton.setEnabled(true);\r
          \r
              ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
              ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
                  String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
                  if (mFile.getRemotePath().equals(downloadedRemotePath)) {\r
                      if (downloadWasFine) {\r
-                         mFile.setStoragePath(intent.getStringExtra(FileDownloader.EXTRA_FILE_PATH));    // updates the local object without accessing the database again\r
+                         mFile = mStorageManager.getFileByPath(downloadedRemotePath);\r
                      }\r
 -                    updateFileDetails();    // it updates the buttons; must be called although !downloadWasFine\r
 +                    updateFileDetails(false);    // it updates the buttons; must be called although !downloadWasFine\r
                  }\r
              }\r
          }\r
              if (!isEmpty() && accountName.equals(mAccount.name)) {\r
                  boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);\r
                  String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);\r
-                 if (mFile.getRemotePath().equals(uploadRemotePath)) {\r
+                 boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));\r
+                 if (mFile.getRemotePath().equals(uploadRemotePath) ||\r
+                     renamedInUpload) {\r
                      if (uploadWasFine) {\r
-                         FileDataStorageManager fdsm = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
-                         mFile = fdsm.getFileByPath(mFile.getRemotePath());\r
+                         mFile = mStorageManager.getFileByPath(mFile.getRemotePath());\r
+                     }\r
+                     if (renamedInUpload) {\r
+                         String newName = (new File(uploadRemotePath)).getName();\r
+                         Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);\r
+                         msg.show();\r
                      }\r
 -                    updateFileDetails();    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
 +                    updateFileDetails(false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
                  }\r
              }\r
          }\r