From: David A. Velasco Date: Wed, 23 Oct 2013 15:35:07 +0000 (+0200) Subject: Merge branch 'develop' into refresh_folder_contents_when_browsed_into X-Git-Tag: oc-android-1.5.5~155^2~4 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/db87c22150ad8a0697ad5191f379647ca1c8ca50?ds=inline;hp=-c Merge branch 'develop' into refresh_folder_contents_when_browsed_into --- db87c22150ad8a0697ad5191f379647ca1c8ca50 diff --combined res/values/strings.xml index 14f0e1a0,85080147..a83d8e78 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@@ -1,7 -1,6 +1,6 @@@ - ownCloud Password: Username: Login @@@ -27,6 -26,7 +26,7 @@@ Details General + More Add new session Create image thumbnails Select an account @@@ -47,7 -47,14 +47,14 @@@ Logging History This shows the recorded logs Delete History + Help + Recommend to a friend + Feedback + Imprint + "Try %1$s on your smartphone!" + "I want to invite you to use %1$s on your smartphone!\nDownload here: %2$s" + Check Server Account name Server address @@@ -129,7 -136,6 +136,7 @@@ Some local files were forgotten %1$d files out of the %2$s directory could not be copied into As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to. + Folder %1$s does not exist anymore "Move all" "All files were moved" "Some files could not be moved" @@@ -218,6 -224,7 +225,7 @@@ Connecting to authentication server… Follow instructions above to get authenticated The server does not support this authentication method + %1$s does not support multiple accounts Application terminated unexpectedly. Would you like to submit a crash report? Send report diff --combined src/com/owncloud/android/Uploader.java index fe1527a0,7dc64909..a15ef3ab --- a/src/com/owncloud/android/Uploader.java +++ b/src/com/owncloud/android/Uploader.java @@@ -55,6 -55,7 +55,6 @@@ import android.widget.SimpleAdapter import android.widget.Toast; import com.owncloud.android.authentication.AccountAuthenticator; -import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; @@@ -76,7 -77,7 +76,7 @@@ public class Uploader extends ListActiv private ArrayList mStreamsToUpload; private boolean mCreateDir; private String mUploadPath; - private DataStorageManager mStorageManager; + private FileDataStorageManager mStorageManager; private OCFile mFile; private final static int DIALOG_NO_ACCOUNT = 0; @@@ -94,7 -95,7 +94,7 @@@ mParents.add(""); if (prepareStreamsToUpload()) { mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAccountType()); if (accounts.length == 0) { Log_OC.i(TAG, "No ownCloud account is available"); showDialog(DIALOG_NO_ACCOUNT); @@@ -136,7 -137,7 +136,7 @@@ // Settings.ADD_ACCOUNT_SETTINGS // and Settings.EXTRA_AUTHORITIES Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); - intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTHORITY }); + intent.putExtra("authorities", new String[] { MainApp.getAuthTokenType() }); startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); } else { // since in API7 there is no direct call for @@@ -157,15 -158,15 +157,15 @@@ }); return builder.create(); case DIALOG_MULTIPLE_ACCOUNT: - CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; + CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(MainApp.getAccountType()).length]; for (int i = 0; i < ac.length; ++i) { - ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name; + ac[i] = mAccountManager.getAccountsByType(MainApp.getAccountType())[i].name; } builder.setTitle(R.string.common_choose_account); builder.setItems(ac, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which]; + mAccount = mAccountManager.getAccountsByType(MainApp.getAccountType())[which]; mStorageManager = new FileDataStorageManager(mAccount, getContentResolver()); populateDirectoryList(); } @@@ -229,12 -230,12 +229,12 @@@ public void onItemClick(AdapterView parent, View view, int position, long id) { // click on folder in the list Log_OC.d(TAG, "on item click"); - Vector tmpfiles = mStorageManager.getDirectoryContent(mFile); + Vector tmpfiles = mStorageManager.getFolderContent(mFile); if (tmpfiles.size() <= 0) return; // filter on dirtype Vector files = new Vector(); for (OCFile f : tmpfiles) - if (f.isDirectory()) + if (f.isFolder()) files.add(f); if (files.size() < position) { throw new IndexOutOfBoundsException("Incorrect item selected"); @@@ -270,7 -271,7 +270,7 @@@ if (resultCode == RESULT_CANCELED) { finish(); } - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); + Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAuthTokenType()); if (accounts.length == 0) { showDialog(DIALOG_NO_ACCOUNT); } else { @@@ -294,11 -295,11 +294,11 @@@ mFile = mStorageManager.getFileByPath(full_path); if (mFile != null) { - Vector files = mStorageManager.getDirectoryContent(mFile); + Vector files = mStorageManager.getFolderContent(mFile); List> data = new LinkedList>(); for (OCFile f : files) { HashMap h = new HashMap(); - if (f.isDirectory()) { + if (f.isFolder()) { h.put("dirname", f.getFileName()); data.add(h); } diff --combined src/com/owncloud/android/datamodel/FileDataStorageManager.java index 9a4ae4b7,a067f107..6597616a --- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@@ -20,13 -20,13 +20,13 @@@ package com.owncloud.android.datamodel import java.io.File; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; -import java.util.List; import java.util.Vector; import com.owncloud.android.Log_OC; - import com.owncloud.android.db.ProviderMeta; + import com.owncloud.android.MainApp; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; import com.owncloud.android.utils.FileStorageUtils; @@@ -35,62 -35,33 +35,62 @@@ import android.content.ContentProviderC import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentResolver; +import android.content.ContentUris; import android.content.ContentValues; import android.content.OperationApplicationException; import android.database.Cursor; import android.net.Uri; import android.os.RemoteException; -public class FileDataStorageManager implements DataStorageManager { +public class FileDataStorageManager { + + public static final int ROOT_PARENT_ID = 0; private ContentResolver mContentResolver; - private ContentProviderClient mContentProvider; + private ContentProviderClient mContentProviderClient; private Account mAccount; - private static String TAG = "FileDataStorageManager"; + private static String TAG = FileDataStorageManager.class.getSimpleName(); + public FileDataStorageManager(Account account, ContentResolver cr) { - mContentProvider = null; + mContentProviderClient = null; mContentResolver = cr; mAccount = account; } public FileDataStorageManager(Account account, ContentProviderClient cp) { - mContentProvider = cp; + mContentProviderClient = cp; mContentResolver = null; mAccount = account; } - @Override + + public void setAccount(Account account) { + mAccount = account; + } + + public Account getAccount() { + return mAccount; + } + + public void setContentResolver(ContentResolver cr) { + mContentResolver = cr; + } + + public ContentResolver getContentResolver() { + return mContentResolver; + } + + public void setContentProviderClient(ContentProviderClient cp) { + mContentProviderClient = cp; + } + + public ContentProviderClient getContentProviderClient() { + return mContentProviderClient; + } + + public OCFile getFileByPath(String path) { Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path); OCFile file = null; @@@ -98,13 -69,22 +98,13 @@@ file = createFileInstance(c); } c.close(); - if (file == null && OCFile.PATH_SEPARATOR.equals(path)) { + if (file == null && OCFile.ROOT_PATH.equals(path)) { return createRootDir(); // root should always exist } return file; } - private OCFile createRootDir() { - OCFile file = new OCFile(OCFile.PATH_SEPARATOR); - file.setMimetype("DIR"); - file.setParentId(DataStorageManager.ROOT_PARENT_ID); - saveFile(file); - return file; - } - - @Override public OCFile getFileById(long id) { Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id)); OCFile file = null; @@@ -125,42 -105,17 +125,42 @@@ return file; } - @Override public boolean fileExists(long id) { return fileExists(ProviderTableMeta._ID, String.valueOf(id)); } - @Override public boolean fileExists(String path) { return fileExists(ProviderTableMeta.FILE_PATH, path); } - @Override + + public Vector getFolderContent(OCFile f) { + if (f != null && f.isFolder() && f.getFileId() != -1) { + return getFolderContent(f.getFileId()); + + } else { + return new Vector(); + } + } + + + public Vector getFolderImages(OCFile folder) { + Vector ret = new Vector(); + if (folder != null) { + // TODO better implementation, filtering in the access to database (if possible) instead of here + Vector tmp = getFolderContent(folder); + OCFile current = null; + for (int i=0; i files) { + /** + * Inserts or updates the list of files contained in a given folder. + * ++ * CALLER IS THE RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD. ++ * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED ++ * + * @param folder + * @param files + * @param removeNotUpdated + */ + public void saveFolder(OCFile folder, Collection updatedFiles, Collection filesToRemove) { + + Log_OC.d(TAG, "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size() + " children and " + filesToRemove.size() + " files to remove"); - Iterator filesIt = files.iterator(); - ArrayList operations = new ArrayList(files.size()); - OCFile file = null; + ArrayList operations = new ArrayList(updatedFiles.size()); - // prepare operations to perform - while (filesIt.hasNext()) { - file = filesIt.next(); + // prepare operations to insert or update files to save in the given folder + for (OCFile file : updatedFiles) { ContentValues cv = new ContentValues(); cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp()); cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData()); @@@ -263,48 -221,43 +266,21 @@@ cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength()); cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype()); cv.put(ProviderTableMeta.FILE_NAME, file.getFileName()); - if (file.getParentId() != 0) - cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); + //cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId()); + cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId()); cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath()); - if (!file.isDirectory()) + if (!file.isFolder()) { cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); + } cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); 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); + cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); - if (fileExists(file.getRemotePath())) { - OCFile oldFile = getFileByPath(file.getRemotePath()); - file.setFileId(oldFile.getFileId()); - - if (file.isDirectory()) { - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, oldFile.getFileLength()); - file.setFileLength(oldFile.getFileLength()); - } - - operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). - withValues(cv). - withSelection( ProviderTableMeta._ID + "=?", - new String[] { String.valueOf(file.getFileId()) }) - .build()); - - } else if (fileExists(file.getFileId())) { - OCFile oldFile = getFileById(file.getFileId()); - if (file.getStoragePath() == null && oldFile.getStoragePath() != null) - file.setStoragePath(oldFile.getStoragePath()); - - if (!file.isDirectory()) - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath()); - else { - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, oldFile.getFileLength()); - file.setFileLength(oldFile.getFileLength()); - } - + boolean existsByPath = fileExists(file.getRemotePath()); + if (existsByPath || fileExists(file.getFileId())) { + // updating an existing file - - /* CALLER IS THE RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD. - * - * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED - */ - /* - OCFile oldFile = null; - if (existsByPath) { - // grant same id - oldFile = getFileByPath(file.getRemotePath()); - file.setFileId(oldFile.getFileId()); - } else { - oldFile = getFileById(file.getFileId()); - } - - if (file.isFolder()) { - // folders keep size information, since it's calculated - file.setFileLength(oldFile.getFileLength()); - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, oldFile.getFileLength()); - - } else if (file.getStoragePath() == null && oldFile.getStoragePath() != null) { - // regular files keep access to local contents, although it's lost in the new OCFile - file.setStoragePath(oldFile.getStoragePath()); - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, oldFile.getStoragePath()); - } - */ - operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). withValues(cv). withSelection( ProviderTableMeta._ID + "=?", @@@ -312,277 -265,81 +288,277 @@@ .build()); } else { + // adding a new file operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build()); } } + + // prepare operations to remove files in the given folder + String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?"; + String [] whereArgs = null; + for (OCFile file : filesToRemove) { + if (file.getParentId() == folder.getFileId()) { + whereArgs = new String[]{mAccount.name, file.getRemotePath()}; + //Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, "" + file.getFileId()); + if (file.isFolder()) { + operations.add(ContentProviderOperation + .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, file.getFileId())).withSelection(where, whereArgs) + .build()); + // TODO remove local folder + } else { + operations.add(ContentProviderOperation + .newDelete(ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId())).withSelection(where, whereArgs) + .build()); + if (file.isDown()) { + new File(file.getStoragePath()).delete(); + // TODO move the deletion of local contents after success of deletions + } + } + } + } + + // update metadata of folder + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp()); + cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, folder.getModificationTimestampAtLastSyncForData()); + cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp()); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0); // FileContentProvider calculates the right size + cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimetype()); + cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName()); + cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId()); + cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath()); + cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); + cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties()); + cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData()); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.keepInSync() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag()); + operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). + withValues(cv). + withSelection( ProviderTableMeta._ID + "=?", + new String[] { String.valueOf(folder.getFileId()) }) + .build()); // apply operations in batch ContentProviderResult[] results = null; + Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); try { if (getContentResolver() != null) { - results = getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations); + results = getContentResolver().applyBatch(MainApp.getAuthority(), operations); } else { - results = getContentProvider().applyBatch(operations); + results = getContentProviderClient().applyBatch(operations); } } catch (OperationApplicationException e) { - Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage()); + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); } catch (RemoteException e) { - Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage()); + Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage()); } // update new id in file objects for insertions if (results != null) { long newId; + Iterator filesIt = updatedFiles.iterator(); + OCFile file = null; for (int i=0; i FileDataStorageManager.ROOT_PARENT_ID) { + Log_OC.d(TAG, "Updating size of " + id); + if (getContentResolver() != null) { + getContentResolver().update(ProviderTableMeta.CONTENT_URI_DIR, null, + ProviderTableMeta._ID + "=?", + new String[] { String.valueOf(id) }); + } else { + try { + getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_DIR, null, + ProviderTableMeta._ID + "=?", + new String[] { String.valueOf(id) }); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Exception in update of folder size through compatibility patch " + e.getMessage()); + } + } + } else { + Log_OC.e(TAG, "not updating size for folder " + id); + } } + - public void setAccount(Account account) { - mAccount = account; + public void removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) { + if (file != null) { + if (file.isFolder()) { + removeFolder(file, removeDBData, removeLocalCopy); + + } else { + if (removeDBData) { + //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId()); + Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId()); + String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?"; + String [] whereArgs = new String[]{mAccount.name, file.getRemotePath()}; + if (getContentProviderClient() != null) { + try { + getContentProviderClient().delete(file_uri, where, whereArgs); + } catch (RemoteException e) { + e.printStackTrace(); + } + } else { + getContentResolver().delete(file_uri, where, whereArgs); + } + updateFolderSize(file.getParentId()); + } + if (removeLocalCopy && file.isDown()) { + boolean success = new File(file.getStoragePath()).delete(); + if (!removeDBData && success) { + // maybe unnecessary, but should be checked TODO remove if unnecessary + file.setStoragePath(null); + saveFile(file); + } + } + } + } } + - public Account getAccount() { - return mAccount; + public void removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) { + if (folder != null && folder.isFolder()) { + if (removeDBData && folder.getFileId() != -1) { + removeFolderInDb(folder); + } + if (removeLocalContent) { + File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder)); + removeLocalFolder(localFolder); + } + } } - public void setContentResolver(ContentResolver cr) { - mContentResolver = cr; + private void removeFolderInDb(OCFile folder) { + Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, ""+ folder.getFileId()); // URI for recursive deletion + String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?" + " AND " + ProviderTableMeta.FILE_PATH + "=?"; + String [] whereArgs = new String[]{mAccount.name, folder.getRemotePath()}; + if (getContentProviderClient() != null) { + try { + getContentProviderClient().delete(folder_uri, where, whereArgs); + } catch (RemoteException e) { + e.printStackTrace(); + } + } else { + getContentResolver().delete(folder_uri, where, whereArgs); + } + updateFolderSize(folder.getParentId()); } - public ContentResolver getContentResolver() { - return mContentResolver; + private void removeLocalFolder(File folder) { + if (folder.exists()) { + File[] files = folder.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + removeLocalFolder(file); + } else { + file.delete(); + } + } + } + folder.delete(); + } } - public void setContentProvider(ContentProviderClient cp) { - mContentProvider = cp; - } + /** + * Updates database for a folder that was moved to a different location. + * + * TODO explore better (faster) implementations + * TODO throw exceptions up ! + */ + public void moveFolder(OCFile folder, String newPath) { + // TODO check newPath - public ContentProviderClient getContentProvider() { - return mContentProvider; - } - - @Override - public Vector getDirectoryContent(OCFile f) { - if (f != null && f.isDirectory() && f.getFileId() != -1) { - return getDirectoryContent(f.getFileId()); + if (folder != null && folder.isFolder() && folder.fileExists() && !OCFile.ROOT_PATH.equals(folder.getFileName())) { + /// 1. get all the descendants of 'dir' in a single QUERY (including 'dir') + Cursor c = null; + if (getContentProviderClient() != null) { + try { + c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ? ", + new String[] { mAccount.name, folder.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC "); + } catch (RemoteException e) { + Log_OC.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, folder.getRemotePath() + "%" }, ProviderTableMeta.FILE_PATH + " ASC "); + } + + /// 2. prepare a batch of update operations to change all the descendants + ArrayList operations = new ArrayList(c.getCount()); + int lengthOfOldPath = folder.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); ++ getContentResolver().applyBatch(MainApp.getAuthority(), operations); + + } else { + getContentProviderClient().applyBatch(operations); + } + + } catch (OperationApplicationException e) { + Log_OC.e(TAG, "Fail to update descendants of " + folder.getFileId() + " in database", e); + + } catch (RemoteException e) { + Log_OC.e(TAG, "Fail to update desendants of " + folder.getFileId() + " in database", e); + } - } else { - return new Vector(); } } - private Vector getDirectoryContent(long parentId) { + + private Vector getFolderContent(long parentId) { Vector ret = new Vector(); @@@ -591,9 -348,9 +567,9 @@@ String.valueOf(parentId)); Cursor c = null; - if (getContentProvider() != null) { + if (getContentProviderClient() != null) { try { - c = getContentProvider().query(req_uri, null, + c = getContentProviderClient().query(req_uri, null, ProviderTableMeta.FILE_PARENT + "=?" , new String[] { String.valueOf(parentId)}, null); } catch (RemoteException e) { @@@ -621,13 -378,6 +597,13 @@@ } + private OCFile createRootDir() { + OCFile file = new OCFile(OCFile.ROOT_PATH); + file.setMimetype("DIR"); + file.setParentId(FileDataStorageManager.ROOT_PARENT_ID); + saveFile(file); + return file; + } private boolean fileExists(String cmp_key, String value) { Cursor c; @@@ -641,7 -391,7 +617,7 @@@ new String[] { value, mAccount.name }, null); } else { try { - c = getContentProvider().query( + c = getContentProviderClient().query( ProviderTableMeta.CONTENT_URI, null, cmp_key + "=? AND " @@@ -671,7 -421,7 +647,7 @@@ new String[] { value, mAccount.name }, null); } else { try { - c = getContentProvider().query( + c = getContentProviderClient().query( ProviderTableMeta.CONTENT_URI, null, key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER @@@ -695,7 -445,7 +671,7 @@@ .getColumnIndex(ProviderTableMeta.FILE_PARENT))); file.setMimetype(c.getString(c .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE))); - if (!file.isDirectory()) { + if (!file.isFolder()) { file.setStoragePath(c.getString(c .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH))); if (file.getStoragePath() == null) { @@@ -721,53 -471,219 +697,10 @@@ getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA))); file.setKeepInSync(c.getInt( c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false); + file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG))); + } return file; } - /* - @Override - public void removeFile(OCFile file, boolean removeLocalCopy) { - Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId()); - if (getContentProvider() != null) { - try { - getContentProvider().delete(file_uri, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}); - } catch (RemoteException e) { - e.printStackTrace(); - } - } else { - getContentResolver().delete(file_uri, - ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?", - new String[]{mAccount.name}); - } - if (file.isDown() && removeLocalCopy) { - new File(file.getStoragePath()).delete(); - } - if (file.isDirectory() && removeLocalCopy) { - File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)); - if (f.exists() && f.isDirectory() && (f.list() == null || f.list().length == 0)) { - f.delete(); - } - } - - if (file.getFileLength() > 0) { - updateSizesToTheRoot(file.getParentId()); - } - } - - @Override - public void removeDirectory(OCFile dir, boolean removeDBData, boolean removeLocalContent) { - // TODO consider possible failures - if (dir != null && dir.isDirectory() && dir.getFileId() != -1) { - Vector children = getDirectoryContent(dir); - if (children.size() > 0) { - OCFile child = null; - for (int i=0; i 0) { - updateSizesToTheRoot(dir.getParentId()); - } - } - } - - - /** - * 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() + "%" }, ProviderTableMeta.FILE_PATH + " ASC "); - } catch (RemoteException e) { - Log_OC.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() + "%" }, ProviderTableMeta.FILE_PATH + " ASC "); - } - - /// 2. prepare a batch of update operations to change all the descendants - ArrayList operations = new ArrayList(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(MainApp.getAuthority(), operations); - - } else { - getContentProvider().applyBatch(operations); - } - - } catch (OperationApplicationException e) { - Log_OC.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e); - - } catch (RemoteException e) { - Log_OC.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e); - } - - } - } - - @Override - public Vector getDirectoryImages(OCFile directory) { - Vector ret = new Vector(); - if (directory != null) { - // TODO better implementation, filtering in the access to database (if possible) instead of here - Vector tmp = getDirectoryContent(directory); - OCFile current = null; - for (int i=0; i files = getDirectoryContent(id); - - for (OCFile f: files) - { - folderSize = folderSize + f.getFileLength(); - } - - updateSize(id, folderSize); - } - - /** -- * Update the size value of an OCFile in DB - * - */ -- private int updateSize(long id, long size) { -- ContentValues cv = new ContentValues(); -- cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, size); -- int result = -1; -- if (getContentResolver() != null) { -- result = getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, ProviderTableMeta._ID + "=?", -- new String[] { String.valueOf(id) }); -- } else { -- try { - result = getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, ProviderTableMeta._ID + "=?", - result = getContentProvider().update(ProviderTableMeta.CONTENT_URI, cv, ProviderTableMeta._ID + "=?", -- new String[] { String.valueOf(id) }); -- } catch (RemoteException e) { -- Log_OC.e(TAG,"Fail to update size column into database " + e.getMessage()); -- } -- } -- return result; -- } - */ -- - /* - /** -- * Update the size of a subtree of folder from a file to the root -- * @param parentId: parent of the file - * - */ -- private void updateSizesToTheRoot(long parentId) { -- -- OCFile file; -- - while (parentId != FileDataStorageManager.ROOT_PARENT_ID) { - while (parentId != 0) { -- -- // Update the size of the parent - updateFolderSize(parentId); - calculateFolderSize(parentId); -- -- // search the next parent -- file = getFileById(parentId); -- parentId = file.getParentId(); -- -- } - -- } - */ -- } diff --combined src/com/owncloud/android/db/ProviderMeta.java index 521d4bbd,a082a84e..8701ebd2 --- a/src/com/owncloud/android/db/ProviderMeta.java +++ b/src/com/owncloud/android/db/ProviderMeta.java @@@ -17,6 -17,8 +17,8 @@@ */ package com.owncloud.android.db; + import com.owncloud.android.MainApp; + import android.net.Uri; import android.provider.BaseColumns; @@@ -28,10 -30,12 +30,12 @@@ */ public class ProviderMeta { - public static final String AUTHORITY_FILES = "org.owncloud"; - public static final String DB_FILE = "owncloud.db"; + /* These constants are now in MainApp + public static final String AUTHORITY_FILES = "org.owncloud"; + public static final String DB_FILE = "owncloud.db"; + */ public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 4; + public static final int DB_VERSION = 5; private ProviderMeta() { } @@@ -39,11 -43,11 +43,11 @@@ static public class ProviderTableMeta implements BaseColumns { public static final String DB_NAME = "filelist"; public static final Uri CONTENT_URI = Uri.parse("content://" - + AUTHORITY_FILES + "/"); + + MainApp.getAuthority() + "/"); public static final Uri CONTENT_URI_FILE = Uri.parse("content://" - + AUTHORITY_FILES + "/file"); + + MainApp.getAuthority() + "/file"); public static final Uri CONTENT_URI_DIR = Uri.parse("content://" - + AUTHORITY_FILES + "/dir"); + + MainApp.getAuthority() + "/dir"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file"; public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file"; @@@ -61,7 -65,6 +65,7 @@@ public static final String FILE_LAST_SYNC_DATE = "last_sync_date"; // _for_properties, but let's keep it as it is public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data"; public static final String FILE_KEEP_IN_SYNC = "keep_in_sync"; + public static final String FILE_ETAG = "etag"; public static final String DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc"; diff --combined src/com/owncloud/android/files/services/FileDownloader.java index a37a86a9,07c4257c..45b49ad2 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@@ -28,7 -28,6 +28,6 @@@ import java.util.Vector import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; - import com.owncloud.android.authentication.AccountAuthenticator; import com.owncloud.android.authentication.AuthenticatorActivity; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@@ -60,6 -59,7 +59,7 @@@ import android.os.Process import android.widget.RemoteViews; import com.owncloud.android.Log_OC; + import com.owncloud.android.MainApp; import com.owncloud.android.R; import eu.alefzero.webdav.WebdavClient; @@@ -68,8 -68,8 +68,8 @@@ public class FileDownloader extends Ser public static final String EXTRA_ACCOUNT = "ACCOUNT"; public static final String EXTRA_FILE = "FILE"; - public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; - public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; + private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED"; + private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH"; public static final String EXTRA_DOWNLOAD_RESULT = "RESULT"; public static final String EXTRA_FILE_PATH = "FILE_PATH"; public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH"; @@@ -92,6 -92,14 +92,14 @@@ private int mLastPercent; + public String getDownloadAddedMessage() { + return getClass().getName().toString() + DOWNLOAD_ADDED_MESSAGE; + } + + public String getDownloadFinishMessage() { + return getClass().getName().toString() + DOWNLOAD_FINISH_MESSAGE; + } + /** * Builds a key for mPendingDownloads from the account and file to download * @@@ -231,7 -239,7 +239,7 @@@ if (account == null || file == null) return false; String targetKey = buildRemoteName(account, file); synchronized (mPendingDownloads) { - if (file.isDirectory()) { + if (file.isFolder()) { // this can be slow if there are many downloads :( Iterator it = mPendingDownloads.keySet().iterator(); boolean found = false; @@@ -467,7 -475,7 +475,7 @@@ boolean needsToUpdateCredentials = (downloadResult.getCode() == ResultCode.UNAUTHORIZED || // (downloadResult.isTemporalRedirection() && downloadResult.isIdPRedirection() (downloadResult.isIdPRedirection() - && AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mDownloadClient.getAuthTokenType()))); + && MainApp.getAuthTokenTypeSamlSessionCookie().equals(mDownloadClient.getAuthTokenType()))); if (needsToUpdateCredentials) { // let the user update credentials with one click Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class); @@@ -515,7 -523,7 +523,7 @@@ * @param downloadResult Result of the download operation */ private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) { - Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE); + Intent end = new Intent(getDownloadFinishMessage()); end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess()); end.putExtra(ACCOUNT_NAME, download.getAccount().name); end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); @@@ -530,7 -538,7 +538,7 @@@ * @param download Added download operation */ private void sendBroadcastNewDownload(DownloadFileOperation download) { - Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE); + Intent added = new Intent(getDownloadAddedMessage()); added.putExtra(ACCOUNT_NAME, download.getAccount().name); added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath()); added.putExtra(EXTRA_FILE_PATH, download.getSavePath()); diff --combined src/com/owncloud/android/files/services/FileUploader.java index a10d2179,e738a276..85e8df0a --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@@ -71,6 -71,7 +71,7 @@@ import android.webkit.MimeTypeMap import android.widget.RemoteViews; import com.owncloud.android.Log_OC; + import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.db.DbHandler; import com.owncloud.android.ui.activity.FailedUploadActivity; @@@ -84,7 -85,7 +85,7 @@@ import eu.alefzero.webdav.WebdavClient public class FileUploader extends Service implements OnDatatransferProgressListener { - public static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH"; + private static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH"; 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"; @@@ -127,6 -128,11 +128,11 @@@ private int mLastPercent; private RemoteViews mDefaultNotificationContentView; + + public String getUploadFinishMessage() { + return getClass().getName().toString() + UPLOAD_FINISH_MESSAGE; + } + /** * Builds a key for mPendingUploads from the account and file to upload * @@@ -377,7 -383,7 +383,7 @@@ return false; String targetKey = buildRemoteName(account, file); synchronized (mPendingUploads) { - if (file.isDirectory()) { + if (file.isFolder()) { // this can be slow if there are many uploads :( Iterator it = mPendingUploads.keySet().iterator(); boolean found = false; @@@ -816,7 -822,7 +822,7 @@@ boolean needsToUpdateCredentials = (uploadResult.getCode() == ResultCode.UNAUTHORIZED || //(uploadResult.isTemporalRedirection() && uploadResult.isIdPRedirection() && (uploadResult.isIdPRedirection() && - AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mUploadClient.getAuthTokenType()))); + MainApp.getAuthTokenTypeSamlSessionCookie().equals(mUploadClient.getAuthTokenType()))); if (needsToUpdateCredentials) { // let the user update credentials with one click Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class); @@@ -899,7 -905,7 +905,7 @@@ * @param uploadResult Result of the upload operation */ private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) { - Intent end = new Intent(UPLOAD_FINISH_MESSAGE); + Intent end = new Intent(getUploadFinishMessage()); end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath()); // real remote // path, after // possible diff --combined src/com/owncloud/android/operations/RemoteOperation.java index e05dadff,191bde0a..604d62ea --- a/src/com/owncloud/android/operations/RemoteOperation.java +++ b/src/com/owncloud/android/operations/RemoteOperation.java @@@ -21,7 -21,7 +21,7 @@@ import java.io.IOException import org.apache.commons.httpclient.Credentials; import com.owncloud.android.Log_OC; - import com.owncloud.android.authentication.AccountAuthenticator; + import com.owncloud.android.MainApp; import com.owncloud.android.network.BearerCredentials; import com.owncloud.android.network.OwnCloudClientUtils; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; @@@ -136,8 -136,14 +136,8 @@@ public abstract class RemoteOperation i mCallerActivity = callerActivity; mClient = null; // the client instance will be created from mAccount and mContext in the runnerThread to create below - if (listener == null) { - throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result"); - } mListener = listener; - if (listenerHandler == null) { - throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread"); - } mListenerHandler = listenerHandler; Thread runnerThread = new Thread(this); @@@ -248,9 -254,9 +248,9 @@@ boolean bearerAuthorization = (cred != null && cred instanceof BearerCredentials); boolean samlBasedSsoAuthorization = (cred == null && ssoSessionCookie != null); if (bearerAuthorization) { - am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ((BearerCredentials)cred).getAccessToken()); + am.invalidateAuthToken(MainApp.getAccountType(), ((BearerCredentials)cred).getAccessToken()); } else if (samlBasedSsoAuthorization ) { - am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ssoSessionCookie); + am.invalidateAuthToken(MainApp.getAccountType(), ssoSessionCookie); } else { am.clearPassword(mAccount); } diff --combined src/com/owncloud/android/providers/FileContentProvider.java index c98bf3a9,b933be4d..8728ef00 --- a/src/com/owncloud/android/providers/FileContentProvider.java +++ b/src/com/owncloud/android/providers/FileContentProvider.java @@@ -18,22 -18,18 +18,23 @@@ package com.owncloud.android.providers; +import java.util.ArrayList; import java.util.HashMap; import com.owncloud.android.Log_OC; + import com.owncloud.android.R; +import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.db.ProviderMeta; import com.owncloud.android.db.ProviderMeta.ProviderTableMeta; import android.content.ContentProvider; +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; +import android.content.OperationApplicationException; import android.content.UriMatcher; import android.database.Cursor; import android.database.SQLException; @@@ -47,7 -43,6 +48,7 @@@ import android.text.TextUtils * The ContentProvider for the ownCloud App. * * @author Bartek Przybylski + * @author David A. Velasco * */ public class FileContentProvider extends ContentProvider { @@@ -84,120 -79,44 +85,110 @@@ ProviderTableMeta.FILE_KEEP_IN_SYNC); mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, ProviderTableMeta.FILE_ACCOUNT_OWNER); + mProjectionMap.put(ProviderTableMeta.FILE_ETAG, + ProviderTableMeta.FILE_ETAG); } private static final int SINGLE_FILE = 1; private static final int DIRECTORY = 2; private static final int ROOT_DIRECTORY = 3; - private static final UriMatcher mUriMatcher; - - private UriMatcher mUriMatcher; -// static { -// mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); -// mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, null, ROOT_DIRECTORY); -// mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); -// mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); -// mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); -// } - public static final String METHOD_UPDATE_FOLDER_SIZE = "updateFolderSize"; ++ private UriMatcher mUriMatcher; - static { - mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, null, ROOT_DIRECTORY); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/", DIRECTORY); - mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY); - } - @Override public int delete(Uri uri, String where, String[] whereArgs) { + //Log_OC.d(TAG, "Deleting " + uri + " at provider " + this); + int count = 0; SQLiteDatabase db = mDbHelper.getWritableDatabase(); + db.beginTransaction(); + try { + count = delete(db, uri, where, whereArgs); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + getContext().getContentResolver().notifyChange(uri, null); + return count; + } + + + private int delete(SQLiteDatabase db, Uri uri, String where, String[] whereArgs) { int count = 0; switch (mUriMatcher.match(uri)) { case SINGLE_FILE: + /*Cursor c = query(db, uri, null, where, whereArgs, null); + String remotePath = "(unexisting)"; + if (c != null && c.moveToFirst()) { + remotePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH)); + } + Log_OC.d(TAG, "Removing FILE " + remotePath); + */ count = db.delete(ProviderTableMeta.DB_NAME, ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1) + (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""), whereArgs); + /* just for log + if (c!=null) { + c.close(); + } + */ + break; + case DIRECTORY: + // deletion of folder is recursive + /* + Uri folderUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, Long.parseLong(uri.getPathSegments().get(1))); + Cursor folder = query(db, folderUri, null, null, null, null); + String folderName = "(unknown)"; + if (folder != null && folder.moveToFirst()) { + folderName = folder.getString(folder.getColumnIndex(ProviderTableMeta.FILE_PATH)); + } + */ + Cursor children = query(uri, null, null, null, null); + if (children != null && children.moveToFirst()) { + long childId; + boolean isDir; + //String remotePath; + while (!children.isAfterLast()) { + childId = children.getLong(children.getColumnIndex(ProviderTableMeta._ID)); + isDir = "DIR".equals(children.getString(children.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE))); + //remotePath = children.getString(children.getColumnIndex(ProviderTableMeta.FILE_PATH)); + if (isDir) { + count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, childId), null, null); + } else { + count += delete(db, ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, childId), null, null); + } + children.moveToNext(); + } + children.close(); + } /*else { + Log_OC.d(TAG, "No child to remove in DIRECTORY " + folderName); + } + Log_OC.d(TAG, "Removing DIRECTORY " + folderName + " (or maybe not) "); + */ + count += db.delete(ProviderTableMeta.DB_NAME, + ProviderTableMeta._ID + + "=" + + uri.getPathSegments().get(1) + + (!TextUtils.isEmpty(where) ? " AND (" + where + + ")" : ""), whereArgs); + /* Just for log + if (folder != null) { + folder.close(); + }*/ break; case ROOT_DIRECTORY: + //Log_OC.d(TAG, "Removing ROOT!"); count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs); break; default: + //Log_OC.e(TAG, "Unknown uri " + uri); throw new IllegalArgumentException("Unknown uri: " + uri.toString()); } - getContext().getContentResolver().notifyChange(uri, null); return count; } + @Override public String getType(Uri uri) { @@@ -214,61 -133,41 +205,70 @@@ @Override public Uri insert(Uri uri, ContentValues values) { + //Log_OC.d(TAG, "Inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); + Uri newUri = null; + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + db.beginTransaction(); + try { + newUri = insert(db, uri, values); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + getContext().getContentResolver().notifyChange(newUri, null); + return newUri; + } + + private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) { if (mUriMatcher.match(uri) != SINGLE_FILE && - mUriMatcher.match(uri) != ROOT_DIRECTORY) { - + mUriMatcher.match(uri) != ROOT_DIRECTORY) { + //Log_OC.e(TAG, "Inserting invalid URI: " + uri); throw new IllegalArgumentException("Unknown uri id: " + uri); } - SQLiteDatabase db = mDbHelper.getWritableDatabase(); long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values); if (rowId > 0) { - Uri insertedFileUri = ContentUris.withAppendedId( - ProviderTableMeta.CONTENT_URI_FILE, rowId); - getContext().getContentResolver().notifyChange(insertedFileUri, - null); + Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId); + //Log_OC.d(TAG, "Inserted " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); return insertedFileUri; + } else { + //Log_OC.d(TAG, "Error while inserting " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); + throw new SQLException("ERROR " + uri); } - throw new SQLException("ERROR " + uri); } + @Override public boolean onCreate() { mDbHelper = new DataBaseHelper(getContext()); + + String authority = getContext().getResources().getString(R.string.authority); + mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + mUriMatcher.addURI(authority, null, ROOT_DIRECTORY); + mUriMatcher.addURI(authority, "file/", SINGLE_FILE); + mUriMatcher.addURI(authority, "file/#", SINGLE_FILE); ++ mUriMatcher.addURI(authority, "dir/", DIRECTORY); + mUriMatcher.addURI(authority, "dir/#", DIRECTORY); + return true; } + @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + Cursor result = null; + SQLiteDatabase db = mDbHelper.getReadableDatabase(); + db.beginTransaction(); + try { + result = query(db, uri, projection, selection, selectionArgs, sortOrder); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return result; + } + + private Cursor query(SQLiteDatabase db, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); sqlQuery.setTables(ProviderTableMeta.DB_NAME); @@@ -278,9 -177,8 +278,9 @@@ case ROOT_DIRECTORY: break; case DIRECTORY: + String folderId = uri.getPathSegments().get(1); sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "=" - + uri.getPathSegments().get(1)); + + folderId); break; case SINGLE_FILE: if (uri.getPathSegments().size() > 1) { @@@ -299,115 -197,24 +299,115 @@@ order = sortOrder; } - SQLiteDatabase db = mDbHelper.getReadableDatabase(); // DB case_sensitive db.execSQL("PRAGMA case_sensitive_like = true"); - Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, - null, null, order); - + Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order); c.setNotificationUri(getContext().getContentResolver(), uri); - return c; } @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - return mDbHelper.getWritableDatabase().update( - ProviderTableMeta.DB_NAME, values, selection, selectionArgs); + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + + //Log_OC.d(TAG, "Updating " + values.getAsString(ProviderTableMeta.FILE_PATH) + " at provider " + this); + int count = 0; + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + db.beginTransaction(); + try { + count = update(db, uri, values, selection, selectionArgs); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + getContext().getContentResolver().notifyChange(uri, null); + return count; + } + + + private int update(SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs) { + switch (mUriMatcher.match(uri)) { + case DIRECTORY: + return updateFolderSize(db, selectionArgs[0]); + default: + return db.update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs); + } + } + + + private int updateFolderSize(SQLiteDatabase db, String folderId) { + int count = 0; + String [] whereArgs = new String[] { folderId }; + + // read current size saved for the folder + long folderSize = 0; + long folderParentId = -1; + Uri selectFolderUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, folderId); + String[] folderProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT}; + String folderWhere = ProviderTableMeta._ID + "=?"; + Cursor folderCursor = query(db, selectFolderUri, folderProjection, folderWhere, whereArgs, null); + if (folderCursor != null && folderCursor.moveToFirst()) { + folderSize = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH));; + folderParentId = folderCursor.getLong(folderCursor.getColumnIndex(ProviderTableMeta.FILE_PARENT));; + } + folderCursor.close(); + + // read and sum sizes of children + long childrenSize = 0; + Uri selectChildrenUri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, folderId); + String[] childrenProjection = new String[] { ProviderTableMeta.FILE_CONTENT_LENGTH, ProviderTableMeta.FILE_PARENT}; + String childrenWhere = ProviderTableMeta.FILE_PARENT + "=?"; + Cursor childrenCursor = query(db, selectChildrenUri, childrenProjection, childrenWhere, whereArgs, null); + if (childrenCursor != null && childrenCursor.moveToFirst()) { + while (!childrenCursor.isAfterLast()) { + childrenSize += childrenCursor.getLong(childrenCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)); + childrenCursor.moveToNext(); + } + } + childrenCursor.close(); + + // update if needed + if (folderSize != childrenSize) { + Log_OC.d("FileContentProvider", "Updating " + folderSize + " to " + childrenSize); + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, childrenSize); + count = db.update(ProviderTableMeta.DB_NAME, cv, folderWhere, whereArgs); + + // propagate update until root + if (folderParentId > FileDataStorageManager.ROOT_PARENT_ID) { + Log_OC.d("FileContentProvider", "Propagating update to " + folderParentId); + updateFolderSize(db, String.valueOf(folderParentId)); + } else { + Log_OC.d("FileContentProvider", "NOT propagating to " + folderParentId); + } + } else { + Log_OC.d("FileContentProvider", "NOT updating, sizes are " + folderSize + " and " + childrenSize); + } + return count; + } + + + @Override + public ContentProviderResult[] applyBatch (ArrayList operations) throws OperationApplicationException { + Log_OC.d("FileContentProvider", "applying batch in provider " + this + " (temporary: " + isTemporary() + ")" ); + ContentProviderResult[] results = new ContentProviderResult[operations.size()]; + int i=0; + + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + db.beginTransaction(); // it's supposed that transactions can be nested + try { + for (ContentProviderOperation operation : operations) { + results[i] = operation.apply(this, results, i); + i++; + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + Log_OC.d("FileContentProvider", "applied batch in provider " + this); + return results; } + class DataBaseHelper extends SQLiteOpenHelper { public DataBaseHelper(Context context) { @@@ -433,8 -240,7 +433,8 @@@ + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, " + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, " - + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );" + + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER, " + + ProviderTableMeta.FILE_ETAG + " TEXT );" ); } @@@ -488,24 -294,8 +488,24 @@@ } if (!upgraded) Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); + + if (oldVersion < 5 && newVersion >= 5) { + Log_OC.i("SQL", "Entering in the #4 ADD in onUpgrade"); + db.beginTransaction(); + try { + db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME + + " ADD COLUMN " + ProviderTableMeta.FILE_ETAG + " TEXT " + + " DEFAULT NULL"); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + if (!upgraded) + Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion); } - } } diff --combined src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java index 43c0f2f2,72414028..34ef4524 --- a/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java @@@ -19,18 -19,17 +19,14 @@@ package com.owncloud.android.syncadapter; import java.io.IOException; - //import java.net.UnknownHostException; - //import java.util.Date; -import java.util.Date; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; - //import org.apache.http.conn.ConnectionKeepAliveStrategy; - //import org.apache.http.protocol.HttpContext; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.protocol.HttpContext; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.authentication.AccountUtils.AccountNotFoundException; -import com.owncloud.android.datamodel.DataStorageManager; +import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.network.OwnCloudClientUtils; import android.accounts.Account; @@@ -43,13 -42,11 +39,13 @@@ import android.content.Context import eu.alefzero.webdav.WebdavClient; /** - * Base SyncAdapter for OwnCloud Designed to be subclassed for the concrete - * SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc.. + * Base synchronization adapter for ownCloud designed to be subclassed for different + * resource types, like FileSync, ConcatsSync, CalendarSync, etc.. * - * @author sassman + * Implements the standard {@link AbstractThreadedSyncAdapter}. * + * @author sassman + * @author David A. Velasco */ public abstract class AbstractOwnCloudSyncAdapter extends AbstractThreadedSyncAdapter { @@@ -57,8 -54,8 +53,7 @@@ private AccountManager accountManager; private Account account; private ContentProviderClient contentProvider; - //private Date lastUpdated; - private Date lastUpdated; - private DataStorageManager mStoreManager; + private FileDataStorageManager mStoreManager; private WebdavClient mClient = null; @@@ -91,14 -88,60 +86,14 @@@ this.contentProvider = contentProvider; } - public Date getLastUpdated() { - return lastUpdated; - } - - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } - - public void setStorageManager(DataStorageManager storage_manager) { + public void setStorageManager(FileDataStorageManager storage_manager) { mStoreManager = storage_manager; } - public DataStorageManager getStorageManager() { + public FileDataStorageManager getStorageManager() { return mStoreManager; } - protected ConnectionKeepAliveStrategy getKeepAliveStrategy() { - return new ConnectionKeepAliveStrategy() { - public long getKeepAliveDuration(HttpResponse response, - HttpContext context) { - // Change keep alive straategy basing on response: ie - // forbidden/not found/etc - // should have keep alive 0 - // default return: 5s - int statusCode = response.getStatusLine().getStatusCode(); - - // HTTP 400, 500 Errors as well as HTTP 118 - Connection timed - // out - if ((statusCode >= 400 && statusCode <= 418) - || (statusCode >= 421 && statusCode <= 426) - || (statusCode >= 500 && statusCode <= 510) - || statusCode == 118) { - return 0; - } - - return 5 * 1000; - } - }; - } - - protected HttpResponse fireRawRequest(HttpRequest query) - throws ClientProtocolException, OperationCanceledException, - AuthenticatorException, IOException { - /* - * BasicHttpContext httpContext = new BasicHttpContext(); BasicScheme - * basicAuth = new BasicScheme(); - * httpContext.setAttribute("preemptive-auth", basicAuth); - * - * HttpResponse response = getClient().execute(mHost, query, - * httpContext); - */ - return null; - } - protected void initClientForCurrentAccount() throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException { AccountUtils.constructFullURLForAccount(getContext(), account); mClient = OwnCloudClientUtils.createOwnCloudClient(account, getContext()); @@@ -107,55 -150,4 +102,13 @@@ protected WebdavClient getClient() { return mClient; } + + + /* method called by ContactSyncAdapter, that is never used */ + protected HttpResponse fireRawRequest(HttpRequest query) + throws ClientProtocolException, OperationCanceledException, + AuthenticatorException, IOException { - /* - * BasicHttpContext httpContext = new BasicHttpContext(); BasicScheme - * basicAuth = new BasicScheme(); - * httpContext.setAttribute("preemptive-auth", basicAuth); - * - * HttpResponse response = getClient().execute(mHost, query, - * httpContext); - */ + return null; + } + - /* methods never used below */ - /* - public Date getLastUpdated() { - return lastUpdated; - } - - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } - - protected ConnectionKeepAliveStrategy getKeepAliveStrategy() { - return new ConnectionKeepAliveStrategy() { - public long getKeepAliveDuration(HttpResponse response, - HttpContext context) { - // Change keep alive straategy basing on response: ie - // forbidden/not found/etc - // should have keep alive 0 - // default return: 5s - int statusCode = response.getStatusLine().getStatusCode(); - - // HTTP 400, 500 Errors as well as HTTP 118 - Connection timed - // out - if ((statusCode >= 400 && statusCode <= 418) - || (statusCode >= 421 && statusCode <= 426) - || (statusCode >= 500 && statusCode <= 510) - || statusCode == 118) { - return 0; - } - - return 5 * 1000; - } - }; - } - */ } diff --combined src/com/owncloud/android/syncadapter/FileSyncAdapter.java index 04dfbdd6,0d4e4c5a..860b8a3d --- a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java @@@ -27,9 -27,10 +27,9 @@@ import java.util.Map import org.apache.jackrabbit.webdav.DavException; import com.owncloud.android.Log_OC; + import com.owncloud.android.MainApp; import com.owncloud.android.R; - import com.owncloud.android.authentication.AccountAuthenticator; import com.owncloud.android.authentication.AuthenticatorActivity; -import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.operations.RemoteOperationResult; @@@ -43,7 -44,6 +43,7 @@@ import android.accounts.AccountsExcepti import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.AbstractThreadedSyncAdapter; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; @@@ -52,60 -52,36 +52,60 @@@ import android.content.SyncResult import android.os.Bundle; /** - * SyncAdapter implementation for syncing sample SyncAdapter contacts to the - * platform ContactOperations provider. + * Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing + * ownCloud files. + * + * Performs a full synchronization of the account recieved in {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)}. * * @author Bartek Przybylski * @author David A. Velasco */ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { - private final static String TAG = "FileSyncAdapter"; + private final static String TAG = FileSyncAdapter.class.getSimpleName(); - /** - * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation - */ + /** Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation */ private static final int MAX_FAILED_RESULTS = 3; + + /** Time stamp for the current synchronization process, used to distinguish fresh data */ private long mCurrentSyncTime; + + /** Flag made 'true' when a request to cancel the synchronization is received */ private boolean mCancellation; + + /** When 'true' the process was requested by the user through the user interface; when 'false', it was requested automatically by the system */ private boolean mIsManualSync; - private int mFailedResultsCounter; + + /** Counter for failed operations in the synchronization process */ + private int mFailedResultsCounter; + + /** Result of the last failed operation */ private RemoteOperationResult mLastFailedResult; - private SyncResult mSyncResult; + + /** Counter of conflicts found between local and remote files */ private int mConflictsFound; + + /** Counter of failed operations in synchronization of kept-in-sync files */ private int mFailsInFavouritesFound; + + /** Map of remote and local paths to files that where locally stored in a location out of the ownCloud folder and couldn't be copied automatically into it */ private Map mForgottenLocalFiles; + /** {@link SyncResult} instance to return to the system when the synchronization finish */ + private SyncResult mSyncResult; + + /** + * Creates an {@link FileSyncAdapter} + * + * {@inheritDoc} + */ public FileSyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); } + /** * {@inheritDoc} */ @@@ -123,20 -99,20 +123,20 @@@ mForgottenLocalFiles = new HashMap(); mSyncResult = syncResult; mSyncResult.fullSyncRequested = false; - mSyncResult.delayUntil = 60*60*24; // sync after 24h + mSyncResult.delayUntil = 60*60*24; // avoid too many automatic synchronizations this.setAccount(account); this.setContentProvider(provider); - this.setStorageManager(new FileDataStorageManager(account, getContentProvider())); + this.setStorageManager(new FileDataStorageManager(account, provider)); try { this.initClientForCurrentAccount(); } catch (IOException e) { - /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again + /// the account is unknown for the Synchronization Manager, unreachable this context, or can not be authenticated; don't try this again mSyncResult.tooManyRetries = true; notifyFailedSynchronization(); return; } catch (AccountsException e) { - /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again + /// the account is unknown for the Synchronization Manager, unreachable this context, or can not be authenticated; don't try this again mSyncResult.tooManyRetries = true; notifyFailedSynchronization(); return; @@@ -149,10 -125,10 +149,10 @@@ updateOCVersion(); mCurrentSyncTime = System.currentTimeMillis(); if (!mCancellation) { - fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID); + synchronizeFolder(getStorageManager().getFileByPath(OCFile.ROOT_PATH)); } else { - Log_OC.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested"); + Log_OC.d(TAG, "Leaving synchronization before synchronizing the root folder because cancelation request"); } @@@ -166,12 -142,14 +166,12 @@@ /// notify the user about the failure of MANUAL synchronization notifyFailedSynchronization(); - } if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { notifyFailsInFavourites(); } if (mForgottenLocalFiles.size() > 0) { notifyForgottenLocalFiles(); - } sendStickyBroadcast(false, null, mLastFailedResult); // message to signal the end to the UI } @@@ -181,12 -159,8 +181,12 @@@ /** * Called by system SyncManager when a synchronization is required to be cancelled. * - * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder - * fetched will be still saved in the database. See onPerformSync implementation. + * Sets the mCancellation flag to 'true'. THe synchronization will be stopped later, + * before a new folder is fetched. Data of the last folder synchronized will be still + * locally saved. + * + * See {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)} + * and {@link #synchronizeFolder(String, long)}. */ @Override public void onSyncCanceled() { @@@ -209,36 -183,20 +209,36 @@@ /** - * Synchronize the properties of files and folders contained in a remote folder given by remotePath. + * Synchronizes the list of files contained in a folder identified with its remote path. + * + * Fetches the list and properties of the files contained in the given folder, including their + * properties, and updates the local database with them. + * + * Enters in the child folders to synchronize their contents also, following a recursive + * depth first strategy. * - * @param remotePath Remote path to the folder to synchronize. - * @param parentId Database Id of the folder to synchronize. + * @param folder Folder to synchronize. */ - private void fetchData(String remotePath, long parentId) { + private void synchronizeFolder(OCFile folder) { if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult)) return; - // perform folder synchronization - SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( remotePath, + /* + OCFile folder, + long currentSyncTime, + boolean updateFolderProperties, + boolean syncFullAccount, + DataStorageManager dataStorageManager, + Account account, + Context context ) { + + } + */ + // folder synchronization + SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( folder, mCurrentSyncTime, - parentId, + true, getStorageManager(), getAccount(), getContext() @@@ -247,9 -205,8 +247,9 @@@ // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess - sendStickyBroadcast(true, remotePath, null); + sendStickyBroadcast(true, folder.getRemotePath(), null); + // check the result of synchronizing the folder if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) { if (result.getCode() == ResultCode.SYNC_CONFLICT) { @@@ -259,17 -216,17 +259,17 @@@ if (synchFolderOp.getForgottenLocalFiles().size() > 0) { mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles()); } - // synchronize children folders - List children = synchFolderOp.getChildren(); - fetchChildren(children); // beware of the 'hidden' recursion here! - - sendStickyBroadcast(true, remotePath, null); + if (result.isSuccess()) { + // synchronize children folders + List children = synchFolderOp.getChildren(); + fetchChildren(folder, children, synchFolderOp.getRemoteFolderChanged()); // beware of the 'hidden' recursion here! + } } else { + // in failures, the statistics for the global result are updated if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED || - // (result.isTemporalRedirection() && result.isIdPRedirection() && ( result.isIdPRedirection() && - AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(getClient().getAuthTokenType()))) { + MainApp.getAuthTokenTypeSamlSessionCookie().equals(getClient().getAuthTokenType()))) { mSyncResult.stats.numAuthExceptions++; } else if (result.getException() instanceof DavException) { @@@ -303,30 -260,23 +303,30 @@@ } /** - * Synchronize data of folders in the list of received files + * Triggers the synchronization of any folder contained in the list of received files. * - * @param files Files to recursively fetch + * @param files Files to recursively synchronize. */ - private void fetchChildren(List files) { + private void fetchChildren(OCFile parent, List files, boolean parentEtagChanged) { int i; + OCFile newFile = null; + String etag = null; + boolean syncDown = false; for (i=0; i < files.size() && !mCancellation; i++) { - OCFile newFile = files.get(i); - if (newFile.isDirectory()) { - fetchData(newFile.getRemotePath(), newFile.getFileId()); - - // Update folder size on DB - getStorageManager().calculateFolderSize(newFile.getFileId()); + newFile = files.get(i); + if (newFile.isFolder()) { + etag = newFile.getEtag(); + syncDown = (parentEtagChanged || etag == null || etag.length() == 0); + if(syncDown) { + synchronizeFolder(newFile); + // update the size of the parent folder again after recursive synchronization + //getStorageManager().updateFolderSize(parent.getFileId()); + sendStickyBroadcast(true, parent.getRemotePath(), null); // notify again to refresh size in UI + } } } - if (mCancellation && i mDirectories; /** Access point to the cached database for the current ownCloud {@link Account} */ - private DataStorageManager mStorageManager = null; + private FileDataStorageManager mStorageManager = null; private SyncBroadcastReceiver mSyncBroadcastReceiver; private UploadFinishReceiver mUploadFinishReceiver; @@@ -118,7 -118,6 +117,7 @@@ private View mRightFragmentContainer; private static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW"; + private static final String KEY_SYNC_IN_PROGRESS = "SYNC_IN_PROGRESS"; public static final int DIALOG_SHORT_WAIT = 0; private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 1; @@@ -140,7 -139,8 +139,9 @@@ private OCFile mWaitingToPreview; private Handler mHandler; + private boolean mSyncInProgress = false; + private String mDownloadAddedMessage; + private String mDownloadFinishMessage; @Override protected void onCreate(Bundle savedInstanceState) { @@@ -150,6 -150,10 +151,10 @@@ super.onCreate(savedInstanceState); // this calls onAccountChanged() when ownCloud Account is valid mHandler = new Handler(); + + FileDownloader downloader = new FileDownloader(); + mDownloadAddedMessage = downloader.getDownloadAddedMessage(); + mDownloadFinishMessage= downloader.getDownloadFinishMessage(); /// bindings to transference services mUploadConnection = new ListServiceConnection(); @@@ -170,12 -174,10 +175,12 @@@ /// Load of saved instance state if(savedInstanceState != null) { mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW); - + mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS); + } else { mWaitingToPreview = null; - } + mSyncInProgress = false; + } /// USER INTERFACE @@@ -191,8 -193,10 +196,10 @@@ // Action bar setup mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); getSupportActionBar().setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation - setSupportProgressBarIndeterminateVisibility(false); // always AFTER setContentView(...) ; to work around bug in its implementation + setSupportProgressBarIndeterminateVisibility(mSyncInProgress); // always AFTER setContentView(...) ; to work around bug in its implementation + + Log_OC.d(TAG, "onCreate() end"); } @@@ -232,20 -236,27 +239,20 @@@ } if (file == null) { // fall back to root folder - file = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); // never returns null + file = mStorageManager.getFileByPath(OCFile.ROOT_PATH); // never returns null } setFile(file); - mDirectories.clear(); - OCFile fileIt = file; - while(fileIt != null && fileIt.getFileName() != OCFile.PATH_SEPARATOR) { - if (fileIt.isDirectory()) { - mDirectories.add(fileIt.getFileName()); - } - // get parent from path - parentPath = fileIt.getRemotePath().substring(0, fileIt.getRemotePath().lastIndexOf(fileIt.getFileName())); - fileIt = mStorageManager.getFileByPath(parentPath); - } - mDirectories.add(OCFile.PATH_SEPARATOR); + setNavigationListWithFolder(file); if (!stateWasRecovered) { Log_OC.e(TAG, "Initializing Fragments in onAccountChanged.."); initFragmentsWithFile(); + if (file.isFolder()) { + startSyncFolderOperation(file); + } } else { - updateFragmentsVisibility(!file.isDirectory()); - updateNavigationElementsInActionBar(file.isDirectory() ? null : file); + updateFragmentsVisibility(!file.isFolder()); + updateNavigationElementsInActionBar(file.isFolder() ? null : file); } @@@ -255,23 -266,6 +262,23 @@@ } + private void setNavigationListWithFolder(OCFile file) { + mDirectories.clear(); + OCFile fileIt = file; + String parentPath; + while(fileIt != null && fileIt.getFileName() != OCFile.ROOT_PATH) { + if (fileIt.isFolder()) { + mDirectories.add(fileIt.getFileName()); + } + //fileIt = mStorageManager.getFileById(fileIt.getParentId()); + // get parent from path + parentPath = fileIt.getRemotePath().substring(0, fileIt.getRemotePath().lastIndexOf(fileIt.getFileName())); + fileIt = mStorageManager.getFileByPath(parentPath); + } + mDirectories.add(OCFile.PATH_SEPARATOR); + } + + private void createMinFragments() { OCFileListFragment listOfFiles = new OCFileListFragment(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); @@@ -314,7 -308,7 +321,7 @@@ private Fragment chooseInitialSecondFragment(OCFile file) { Fragment secondFragment = null; - if (file != null && !file.isDirectory()) { + if (file != null && !file.isFolder()) { if (file.isDown() && PreviewMediaFragment.canBePreviewed(file) && file.getLastSyncDateForProperties() > 0 // temporal fix ) { @@@ -418,12 -412,12 +425,12 @@@ // the user browsed to other file ; forget the automatic preview mWaitingToPreview = null; - } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) { + } else if (downloadEvent.equals(mDownloadAddedMessage)) { // grant that the right panel updates the progress bar detailsFragment.listenForTransferProgress(); detailsFragment.updateFileDetails(true, false); - } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) { + } else if (downloadEvent.equals(mDownloadFinishMessage)) { // update the right panel boolean detailsFragmentChanged = false; if (waitedPreview) { @@@ -479,9 -473,8 +486,9 @@@ FileFragment second = getSecondFragment(); OCFile currentDir = getCurrentDir(); if((currentDir != null && currentDir.getParentId() != 0) || - (second != null && second.getFile() != null)) { + (second != null && second.getFile() != null)) { onBackPressed(); + } break; } @@@ -492,33 -485,26 +499,33 @@@ } private void startSynchronization() { - ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY); // cancel the current synchronizations of any ownCloud account + ContentResolver.cancelSync(null, MainApp.getAuthTokenType()); // cancel the current synchronizations of any ownCloud account Bundle bundle = new Bundle(); bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); ContentResolver.requestSync( getAccount(), - AccountAuthenticator.AUTHORITY, bundle); + MainApp.getAuthTokenType(), bundle); } @Override public boolean onNavigationItemSelected(int itemPosition, long itemId) { - int i = itemPosition; - while (i-- != 0) { - onBackPressed(); - } - // the next operation triggers a new call to this method, but it's necessary to - // ensure that the name exposed in the action bar is the current directory when the - // user selected it in the navigation list - if (itemPosition != 0) + if (itemPosition != 0) { + String targetPath = ""; + for (int i=itemPosition; i < mDirectories.getCount() - 1; i++) { + targetPath = mDirectories.getItem(i) + OCFile.PATH_SEPARATOR + targetPath; + } + targetPath = OCFile.PATH_SEPARATOR + targetPath; + OCFile targetFolder = mStorageManager.getFileByPath(targetPath); + if (targetFolder != null) { + browseTo(targetFolder); + } + + // the next operation triggers a new call to this method, but it's necessary to + // ensure that the name exposed in the action bar is the current directory when the + // user selected it in the navigation list getSupportActionBar().setSelectedNavigationItem(0); + } return true; } @@@ -623,17 -609,14 +630,17 @@@ finish(); return; } - popDirname(); - listOfFiles.onBrowseUp(); + int levelsUp = listOfFiles.onBrowseUp(); + for (int i=0; i < levelsUp && mDirectories.getCount() > 1 ; i++) { + popDirname(); + } } } if (listOfFiles != null) { // should never be null, indeed setFile(listOfFiles.getCurrentFile()); } cleanSecondFragment(); + } @Override @@@ -642,8 -625,6 +649,8 @@@ Log_OC.e(TAG, "onSaveInstanceState() start"); super.onSaveInstanceState(outState); outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview); + outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress); + Log_OC.d(TAG, "onSaveInstanceState() end"); } @@@ -654,19 -635,22 +661,22 @@@ super.onResume(); Log_OC.e(TAG, "onResume() start"); + FileUploader fileUploader = new FileUploader(); + FileSyncService fileSyncService = new FileSyncService(); + // Listen for sync messages - IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE); + IntentFilter syncIntentFilter = new IntentFilter(fileSyncService.getSyncMessage()); mSyncBroadcastReceiver = new SyncBroadcastReceiver(); registerReceiver(mSyncBroadcastReceiver, syncIntentFilter); // Listen for upload messages - IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); + IntentFilter uploadIntentFilter = new IntentFilter(fileUploader.getUploadFinishMessage()); mUploadFinishReceiver = new UploadFinishReceiver(); registerReceiver(mUploadFinishReceiver, uploadIntentFilter); // Listen for download messages - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE); - downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE); + IntentFilter downloadIntentFilter = new IntentFilter(mDownloadAddedMessage); + downloadIntentFilter.addAction(mDownloadFinishMessage); mDownloadFinishReceiver = new DownloadFinishReceiver(); registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); @@@ -831,10 -815,10 +841,10 @@@ /** * Pushes a directory to the drop down list * @param directory to push - * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false. + * @throws IllegalArgumentException If the {@link OCFile#isFolder()} returns false. */ public void pushDirname(OCFile directory) { - if(!directory.isDirectory()){ + if(!directory.isFolder()){ throw new IllegalArgumentException("Only directories may be pushed!"); } mDirectories.insert(directory.getFileName(), 0); @@@ -886,7 -870,8 +896,7 @@@ public void onReceive(Context context, Intent intent) { boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false); String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME); - - Log_OC.d(TAG, "sync of account " + accountName + " is in_progress: " + inProgress); + RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT); if (getAccount() != null && accountName.equals(getAccount().name) && mStorageManager != null @@@ -894,39 -879,31 +904,39 @@@ String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); - boolean fillBlankRoot = false; - OCFile currentDir = getCurrentDir(); - if (currentDir == null) { - currentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); - fillBlankRoot = (currentDir != null); - } + OCFile currentFile = (getFile() == null) ? null : mStorageManager.getFileByPath(getFile().getRemotePath()); + OCFile currentDir = (getCurrentDir() == null) ? null : mStorageManager.getFileByPath(getCurrentDir().getRemotePath()); - if ((synchFolderRemotePath != null && currentDir != null && (currentDir.getRemotePath().equals(synchFolderRemotePath))) - || fillBlankRoot ) { - if (!fillBlankRoot) - currentDir = mStorageManager.getFileByPath(synchFolderRemotePath); - OCFileListFragment fileListFragment = getListOfFilesFragment(); - if (fileListFragment != null) { - fileListFragment.listDirectory(currentDir); + if (currentDir == null) { + // current folder was removed from the server + Toast.makeText( FileDisplayActivity.this, + String.format(getString(R.string.sync_current_folder_was_removed), mDirectories.getItem(0)), + Toast.LENGTH_LONG) + .show(); + browseToRoot(); + + } else { + if (currentFile == null && !getFile().isFolder()) { + // currently selected file was removed in the server, and now we know it + cleanSecondFragment(); + currentFile = currentDir; } - if (getSecondFragment() == null) - setFile(currentDir); + + if (synchFolderRemotePath != null && currentDir.getRemotePath().equals(synchFolderRemotePath)) { + OCFileListFragment fileListFragment = getListOfFilesFragment(); + if (fileListFragment != null) { + fileListFragment.listDirectory(currentDir); + } + } + setFile(currentFile); } setSupportProgressBarIndeterminateVisibility(inProgress); removeStickyBroadcast(intent); + mSyncInProgress = inProgress; } - - RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT); + if (synchResult != null) { if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) { mLastSslUntrustedServerResult = synchResult; @@@ -935,7 -912,7 +945,7 @@@ } } } - + private class UploadFinishReceiver extends BroadcastReceiver { /** @@@ -995,43 -972,11 +1005,43 @@@ * {@inheritDoc} */ @Override - public DataStorageManager getStorageManager() { + public FileDataStorageManager getStorageManager() { return mStorageManager; } + public void browseToRoot() { + OCFileListFragment listOfFiles = getListOfFilesFragment(); + if (listOfFiles != null) { // should never be null, indeed + while (mDirectories.getCount() > 1) { + popDirname(); + } + OCFile root = mStorageManager.getFileByPath(OCFile.ROOT_PATH); + listOfFiles.listDirectory(root); + setFile(listOfFiles.getCurrentFile()); + startSyncFolderOperation(root); + } + cleanSecondFragment(); + } + + + public void browseTo(OCFile folder) { + if (folder == null || !folder.isFolder()) { + throw new IllegalArgumentException("Trying to browse to invalid folder " + folder); + } + OCFileListFragment listOfFiles = getListOfFilesFragment(); + if (listOfFiles != null) { + setNavigationListWithFolder(folder); + listOfFiles.listDirectory(folder); + setFile(listOfFiles.getCurrentFile()); + startSyncFolderOperation(folder); + } else { + Log_OC.e(TAG, "Unexpected null when accessing list fragment"); + } + cleanSecondFragment(); + } + + /** * {@inheritDoc} * @@@ -1041,10 -986,6 +1051,10 @@@ public void onBrowsedDownTo(OCFile directory) { pushDirname(directory); cleanSecondFragment(); + + // Sync Folder + startSyncFolderOperation(directory); + } /** @@@ -1133,19 -1074,6 +1143,19 @@@ } +// private void updateDisplayHomeAtSync(){ +// ActionBar actionBar = getSupportActionBar(); +// OCFile currentDir = getCurrentDir(); +// if (currentDir.getParentId() != DataStorageManager.ROOT_PARENT_ID) { +// actionBar.setHomeButtonEnabled(!mSyncInProgress); +// actionBar.setDisplayHomeAsUpEnabled(!mSyncInProgress); +// } +// else { +// actionBar.setHomeButtonEnabled(true); +// actionBar.setDisplayHomeAsUpEnabled(false); +// } +// } +// /** * {@inheritDoc} */ @@@ -1266,8 -1194,7 +1276,8 @@@ } else if (operation instanceof CreateFolderOperation) { onCreateFolderOperationFinish((CreateFolderOperation)operation, result); - } + + } } @@@ -1315,6 -1242,7 +1325,6 @@@ refeshListOfFilesFragment(); } else { - //dismissDialog(DIALOG_SHORT_WAIT); dismissLoadingDialog(); try { Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); @@@ -1375,7 -1303,10 +1385,7 @@@ i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, getAccount()); startActivity(i); - } else { - Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); - msg.show(); - } + } } else { if (operation.transferWasRequested()) { @@@ -1444,7 -1375,7 +1454,7 @@@ private OCFile getCurrentDir() { OCFile file = getFile(); if (file != null) { - if (file.isDirectory()) { + if (file.isFolder()) { return file; } else if (mStorageManager != null) { String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName())); @@@ -1453,35 -1384,5 +1463,35 @@@ } return null; } + + public void startSyncFolderOperation(OCFile folder) { + long currentSyncTime = System.currentTimeMillis(); + + mSyncInProgress = true; + + // perform folder synchronization + RemoteOperation synchFolderOp = new SynchronizeFolderOperation( folder, + currentSyncTime, + false, + getStorageManager(), + getAccount(), + getApplicationContext() + ); + synchFolderOp.execute(getAccount(), this, null, null, this); + + setSupportProgressBarIndeterminateVisibility(true); + } + +// public void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) { +// int childCount = viewGroup.getChildCount(); +// for (int i = 0; i < childCount; i++) { +// View view = viewGroup.getChildAt(i); +// view.setEnabled(enabled); +// view.setClickable(!enabled); +// if (view instanceof ViewGroup) { +// enableDisableViewGroup((ViewGroup) view, enabled); +// } +// } +// } } diff --combined src/com/owncloud/android/ui/fragment/FileDetailFragment.java index ae040389,944decfa..c7c5e40a --- a/src/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/com/owncloud/android/ui/fragment/FileDetailFragment.java @@@ -207,7 -207,8 +207,8 @@@ public class FileDetailFragment extend public void onResume() { super.onResume(); mUploadFinishReceiver = new UploadFinishReceiver(); - IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); + FileUploader fileUploader = new FileUploader(); + IntentFilter filter = new IntentFilter(fileUploader.getUploadFinishMessage()); getActivity().registerReceiver(mUploadFinishReceiver, filter); } @@@ -416,7 -417,7 +417,7 @@@ private void renameFile() { OCFile file = getFile(); String fileName = file.getFileName(); - int extensionStart = file.isDirectory() ? -1 : fileName.lastIndexOf("."); + int extensionStart = file.isFolder() ? -1 : fileName.lastIndexOf("."); int selectionEnd = (extensionStart >= 0) ? extensionStart : fileName.length(); EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), fileName, 0, selectionEnd, this); dialog.show(getFragmentManager(), "nameeditdialog"); @@@ -447,7 -448,7 +448,7 @@@ } } else { - mLastRemoteOperation = new SynchronizeFileOperation(file, null, mStorageManager, mAccount, true, false, getActivity()); + mLastRemoteOperation = new SynchronizeFileOperation(file, null, mStorageManager, mAccount, true, getActivity()); mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity()); // update ui @@@ -836,7 -837,10 +837,7 @@@ i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount); startActivity(i); - } else { - Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); - msg.show(); - } + } if (file.isDown()) { setButtonsForDown(); diff --combined src/com/owncloud/android/ui/preview/PreviewImageActivity.java index 4b3364a6,6a80ffbd..1b36017c --- a/src/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/src/com/owncloud/android/ui/preview/PreviewImageActivity.java @@@ -36,6 -36,7 +36,6 @@@ import com.actionbarsherlock.app.Action import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.Window; import com.owncloud.android.authentication.AccountUtils; -import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileDownloader; @@@ -66,7 -67,7 +66,7 @@@ public class PreviewImageActivity exten private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT"; - private DataStorageManager mStorageManager; + private FileDataStorageManager mStorageManager; private ViewPager mViewPager; private PreviewImagePagerAdapter mPreviewImagePagerAdapter; @@@ -81,7 -82,10 +81,10 @@@ private boolean mFullScreen; - + private String mDownloadAddedMessage; + private String mDownloadFinishMessage; + + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@@ -99,6 -103,10 +102,10 @@@ } else { mRequestWaitingForBinder = false; } + + FileDownloader downloader = new FileDownloader(); + mDownloadAddedMessage = downloader.getDownloadAddedMessage(); + mDownloadFinishMessage= downloader.getDownloadFinishMessage(); } private void initViewPager() { @@@ -108,7 -116,7 +115,7 @@@ //OCFile parentFolder = mStorageManager.getFileById(getFile().getParentId()); if (parentFolder == null) { // should not be necessary - parentFolder = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); + parentFolder = mStorageManager.getFileByPath(OCFile.ROOT_PATH); } mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), parentFolder, getAccount(), mStorageManager); mViewPager = (ViewPager) findViewById(R.id.fragmentPager); @@@ -218,8 -226,9 +225,9 @@@ super.onResume(); //Log.e(TAG, "ACTIVITY, ONRESUME"); mDownloadFinishReceiver = new DownloadFinishReceiver(); - IntentFilter filter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE); - filter.addAction(FileDownloader.DOWNLOAD_ADDED_MESSAGE); + + IntentFilter filter = new IntentFilter(mDownloadFinishMessage); + filter.addAction(mDownloadAddedMessage); registerReceiver(mDownloadFinishReceiver, filter); } @@@ -378,7 -387,7 +386,7 @@@ boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false); //boolean isOffscreen = Math.abs((mViewPager.getCurrentItem() - position)) <= mViewPager.getOffscreenPageLimit(); - if (position >= 0 && intent.getAction().equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) { + if (position >= 0 && intent.getAction().equals(mDownloadFinishMessage)) { if (downloadWasFine) { mPreviewImagePagerAdapter.updateFile(position, file); @@@ -433,7 -442,7 +441,7 @@@ mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver()); // Update file according to DB file, if it is possible - if (file.getFileId() > DataStorageManager.ROOT_PARENT_ID) + if (file.getFileId() > FileDataStorageManager.ROOT_PARENT_ID) file = mStorageManager.getFileById(file.getFileId()); if (file != null) { diff --combined src/eu/alefzero/webdav/WebdavClient.java index 320bc526,c0eba542..65a8f00a --- a/src/eu/alefzero/webdav/WebdavClient.java +++ b/src/eu/alefzero/webdav/WebdavClient.java @@@ -42,8 -42,8 +42,8 @@@ import org.apache.http.HttpStatus import org.apache.http.params.CoreProtocolPNames; import com.owncloud.android.Log_OC; + import com.owncloud.android.MainApp; - import com.owncloud.android.authentication.AccountAuthenticator; import com.owncloud.android.network.BearerAuthScheme; import com.owncloud.android.network.BearerCredentials; @@@ -72,7 -72,7 +72,7 @@@ public class WebdavClient extends HttpC getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); mFollowRedirects = true; mSsoSessionCookie = null; - mAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD; + mAuthTokenType = MainApp.getAuthTokenTypePass(); } public void setBearerCredentials(String accessToken) { @@@ -85,7 -85,7 +85,7 @@@ mCredentials = new BearerCredentials(accessToken); getState().setCredentials(AuthScope.ANY, mCredentials); mSsoSessionCookie = null; - mAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN; + mAuthTokenType = MainApp.getAuthTokenTypeAccessToken(); } public void setBasicCredentials(String username, String password) { @@@ -97,7 -97,7 +97,7 @@@ mCredentials = new UsernamePasswordCredentials(username, password); getState().setCredentials(AuthScope.ANY, mCredentials); mSsoSessionCookie = null; - mAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD; + mAuthTokenType = MainApp.getAuthTokenTypePass(); } public void setSsoSessionCookie(String accessToken) { @@@ -105,7 -105,7 +105,7 @@@ getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); mSsoSessionCookie = accessToken; mCredentials = null; - mAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE; + mAuthTokenType = MainApp.getAuthTokenTypeSamlSessionCookie(); } @@@ -168,7 -168,7 +168,7 @@@ try { method.setFollowRedirects(mFollowRedirects); } catch (Exception e) { - if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used"); + //if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used if needed"); customRedirectionNeeded = mFollowRedirects; } if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) {