Merge remote-tracking branch 'remotes/upstream/master' into beta
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / FileDataStorageManager.java
index 5d49b2c..3e07375 100644 (file)
 
 package com.owncloud.android.datamodel;
 
 
 package com.owncloud.android.datamodel;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-
 import android.accounts.Account;
 import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
 import android.accounts.Account;
 import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
@@ -47,18 +37,26 @@ import android.provider.MediaStore;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
 import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.files.FileUtils;
 import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.lib.resources.shares.ShareType;
 import com.owncloud.android.lib.resources.status.CapabilityBooleanType;
 import com.owncloud.android.lib.resources.status.OCCapability;
 import com.owncloud.android.utils.FileStorageUtils;
 
 import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.lib.resources.shares.ShareType;
 import com.owncloud.android.lib.resources.status.CapabilityBooleanType;
 import com.owncloud.android.lib.resources.status.OCCapability;
 import com.owncloud.android.utils.FileStorageUtils;
 
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
 
 public class FileDataStorageManager {
 
 
 public class FileDataStorageManager {
 
@@ -144,10 +142,9 @@ public class FileDataStorageManager {
     }
 
 
     }
 
 
-    public Vector<OCFile> getFolderContent(OCFile f/*, boolean onlyOnDevice*/) {
+    public Vector<OCFile> getFolderContent(OCFile f, boolean onlyOnDevice) {
         if (f != null && f.isFolder() && f.getFileId() != -1) {
         if (f != null && f.isFolder() && f.getFileId() != -1) {
-            // TODO Enable when "On Device" is recovered ?
-            return getFolderContent(f.getFileId()/*, onlyOnDevice*/);
+            return getFolderContent(f.getFileId(), onlyOnDevice);
 
         } else {
             return new Vector<OCFile>();
 
         } else {
             return new Vector<OCFile>();
@@ -155,13 +152,12 @@ public class FileDataStorageManager {
     }
 
 
     }
 
 
-    public Vector<OCFile> getFolderImages(OCFile folder/*, boolean onlyOnDevice*/) {
-        Vector<OCFile> ret = new Vector<OCFile>();
+    public Vector<OCFile> getFolderImages(OCFile folder, boolean onlyOnDevice) {
+        Vector<OCFile> ret = new Vector<OCFile>(); 
         if (folder != null) {
             // TODO better implementation, filtering in the access to database instead of here
         if (folder != null) {
             // TODO better implementation, filtering in the access to database instead of here
-            // TODO Enable when "On Device" is recovered ?
-            Vector<OCFile> tmp = getFolderContent(folder/*, onlyOnDevice*/);
-            OCFile current = null;
+            Vector<OCFile> tmp = getFolderContent(folder, onlyOnDevice);
+            OCFile current = null; 
             for (int i=0; i<tmp.size(); i++) {
                 current = tmp.get(i);
                 if (current.isImage()) {
             for (int i=0; i<tmp.size(); i++) {
                 current = tmp.get(i);
                 if (current.isImage()) {
@@ -515,8 +511,7 @@ public class FileDataStorageManager {
         File localFolder = new File(localFolderPath);
         if (localFolder.exists()) {
             // stage 1: remove the local files already registered in the files database
         File localFolder = new File(localFolderPath);
         if (localFolder.exists()) {
             // stage 1: remove the local files already registered in the files database
-            // TODO Enable when "On Device" is recovered ?
-            Vector<OCFile> files = getFolderContent(folder.getFileId()/*, false*/);
+            Vector<OCFile> files = getFolderContent(folder.getFileId(), false);
             if (files != null) {
                 for (OCFile file : files) {
                     if (file.isFolder()) {
             if (files != null) {
                 for (OCFile file : files) {
                     if (file.isFolder()) {
@@ -714,46 +709,78 @@ public class FileDataStorageManager {
                 if (!targetFolder.exists()) {
                     targetFolder.mkdirs();
                 }
                 if (!targetFolder.exists()) {
                     targetFolder.mkdirs();
                 }
-                copied = copyFile(localFile, targetFile);
+                copied = FileStorageUtils.copyFile(localFile, targetFile);
             }
             Log_OC.d(TAG, "Local file COPIED : " + copied);
         }
     }
 
             }
             Log_OC.d(TAG, "Local file COPIED : " + copied);
         }
     }
 
-    private boolean copyFile(File src, File target) {
-        boolean ret = true;
+    public void migrateStoredFiles(String srcPath, String dstPath) throws Exception {
+        Cursor c = null;
+        if (getContentResolver() != null) {
+            c = getContentResolver().query(ProviderTableMeta.CONTENT_URI_FILE,
+                    null,
+                    ProviderTableMeta.FILE_STORAGE_PATH  + " IS NOT NULL",
+                    null,
+                    null);
+
+        } else {
+            try {
+                c = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI_FILE,
+                        new String[]{ProviderTableMeta._ID, ProviderTableMeta.FILE_STORAGE_PATH},
+                        ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL",
+                        null,
+                        null);
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, e.getMessage());
+                throw e;
+            }
+        }
+
+        ArrayList<ContentProviderOperation> operations =
+                new ArrayList<ContentProviderOperation>(c.getCount());
+        if (c.moveToFirst()) {
+            do {
+                ContentValues cv = new ContentValues();
+                long fileId = c.getLong(c.getColumnIndex(ProviderTableMeta._ID));
+                String oldFileStoragePath = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
+
+                if (oldFileStoragePath.startsWith(srcPath)) {
 
 
-        InputStream in = null;
-        OutputStream out = null;
+                    cv.put(
+                            ProviderTableMeta.FILE_STORAGE_PATH,
+                            oldFileStoragePath.replaceFirst(srcPath, dstPath));
 
 
+                    operations.add(
+                            ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
+                                    withValues(cv).
+                                    withSelection(
+                                            ProviderTableMeta._ID + "=?",
+                                            new String[]{String.valueOf(fileId)}
+                                    )
+                                    .build());
+                }
+
+            } while (c.moveToNext());
+        }
+        c.close();
+
+        /// 3. apply updates in batch
         try {
         try {
-            in = new FileInputStream(src);
-            out = new FileOutputStream(target);
-            byte[] buf = new byte[1024];
-            int len;
-            while ((len = in.read(buf)) > 0) {
-                out.write(buf, 0, len);
-            }
-        } catch (IOException ex) {
-            ret = false;
-        } finally {
-            if (in != null) try {
-                in.close();
-            } catch (IOException e) {
-                e.printStackTrace(System.err);
-            }
-            if (out != null) try {
-                out.close();
-            } catch (IOException e) {
-                e.printStackTrace(System.err);
+            if (getContentResolver() != null) {
+                getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+            } else {
+                getContentProviderClient().applyBatch(operations);
             }
             }
-        }
 
 
-        return ret;
+        } catch (Exception e) {
+            throw e;
+        }
     }
 
     }
 
-
-    private Vector<OCFile> getFolderContent(long parentId/*, boolean onlyOnDevice*/) {
+    
+    private Vector<OCFile> getFolderContent(long parentId, boolean onlyOnDevice) {
 
         Vector<OCFile> ret = new Vector<OCFile>();
 
 
         Vector<OCFile> ret = new Vector<OCFile>();
 
@@ -780,10 +807,9 @@ public class FileDataStorageManager {
         if (c.moveToFirst()) {
             do {
                 OCFile child = createFileInstance(c);
         if (c.moveToFirst()) {
             do {
                 OCFile child = createFileInstance(c);
-                // TODO Enable when "On Device" is recovered ?
-                // if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
-                ret.add(child);
-                // }
+                 if (child.isFolder() || !onlyOnDevice || onlyOnDevice && child.isDown()){
+                    ret.add(child);
+                 }
             } while (c.moveToNext());
         }
 
             } while (c.moveToNext());
         }
 
@@ -935,20 +961,20 @@ public class FileDataStorageManager {
         );
         cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
         cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
         );
         cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
         cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
-        cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
+        cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getRemoteId());
         cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
         cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
-        if (shareExists(share.getIdRemoteShared())) {// for renamed files; no more delete and create
+        if (shareExists(share.getRemoteId())) {// for renamed files; no more delete and create
             overriden = true;
             if (getContentResolver() != null) {
                 getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv,
                         ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
             overriden = true;
             if (getContentResolver() != null) {
                 getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv,
                         ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
-                        new String[]{String.valueOf(share.getIdRemoteShared())});
+                        new String[]{String.valueOf(share.getRemoteId())});
             } else {
                 try {
                     getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_SHARE,
                             cv, ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
             } else {
                 try {
                     getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_SHARE,
                             cv, ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
-                            new String[]{String.valueOf(share.getIdRemoteShared())});
+                            new String[]{String.valueOf(share.getRemoteId())});
                 } catch (RemoteException e) {
                     Log_OC.e(TAG,
                             "Fail to insert insert file to database "
                 } catch (RemoteException e) {
                     Log_OC.e(TAG,
                             "Fail to insert insert file to database "
@@ -981,16 +1007,42 @@ public class FileDataStorageManager {
     }
 
 
     }
 
 
+    /**
+     * Get first share bound to a file with a known path and given {@link ShareType}.
+     *
+     * @param path          Path of the file.
+     * @param type          Type of the share to get
+     * @param shareWith     Target of the share. Ignored in type is {@link ShareType#PUBLIC_LINK}
+     * @return              First {@OCShare} instance found in DB bound to the file in 'path'
+     */
     public OCShare getFirstShareByPathAndType(String path, ShareType type, String shareWith) {
         Cursor c = null;
     public OCShare getFirstShareByPathAndType(String path, ShareType type, String shareWith) {
         Cursor c = null;
+        if (shareWith == null) {
+            shareWith = "";
+        }
 
         String selection = ProviderTableMeta.OCSHARES_PATH + "=? AND "
                 + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
 
         String selection = ProviderTableMeta.OCSHARES_PATH + "=? AND "
                 + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? AND "
-                + ProviderTableMeta.OCSHARES_SHARE_WITH + "=? AND "
                 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" ;
                 + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?" ;
+        if (!ShareType.PUBLIC_LINK.equals(type)) {
+            selection += " AND " + ProviderTableMeta.OCSHARES_SHARE_WITH + "=?";
+        }
 
 
-        String [] selectionArgs =  new String[]{path, Integer.toString(type.getValue()),
-                shareWith, mAccount.name};
+        String [] selectionArgs;
+        if (ShareType.PUBLIC_LINK.equals(type)) {
+            selectionArgs = new String[]{
+                    path,
+                    Integer.toString(type.getValue()),
+                    mAccount.name
+            };
+        } else {
+            selectionArgs = new String[]{
+                    path,
+                    Integer.toString(type.getValue()),
+                    mAccount.name,
+                    shareWith
+            };
+        }
 
         if (getContentResolver() != null) {
             c = getContentResolver().query(
 
         if (getContentResolver() != null) {
             c = getContentResolver().query(
@@ -1190,16 +1242,16 @@ public class FileDataStorageManager {
                 );
                 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
                 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
                 );
                 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
                 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
-                cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
+                cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getRemoteId());
                 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
                 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
-                if (shareExists(share.getIdRemoteShared())) {
+                if (shareExists(share.getRemoteId())) {
                     // updating an existing file
                     operations.add(
                             ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
                                     withValues(cv).
                                     withSelection(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
                     // updating an existing file
                     operations.add(
                             ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
                                     withValues(cv).
                                     withSelection(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
-                                            new String[]{String.valueOf(share.getIdRemoteShared())})
+                                            new String[]{String.valueOf(share.getRemoteId())})
                                     .build());
                 } else {
                     // adding a new file
                                     .build());
                 } else {
                     // adding a new file
@@ -1403,6 +1455,30 @@ public class FileDataStorageManager {
 //        updateSharedFiles(sharedFiles);
     }
 
 //        updateSharedFiles(sharedFiles);
     }
 
+    public void removeSharesForFile(String remotePath) {
+        resetShareFlagInAFile(remotePath);
+        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
+        operations = prepareRemoveSharesInFile(remotePath, operations);
+        // apply operations in batch
+        if (operations.size() > 0) {
+            Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider");
+            try {
+                if (getContentResolver() != null) {
+                    getContentResolver().applyBatch(MainApp.getAuthority(), operations);
+
+                } else {
+                    getContentProviderClient().applyBatch(operations);
+                }
+
+            } catch (OperationApplicationException e) {
+                Log_OC.e(TAG, "Exception in batch of operations " + e.getMessage());
+
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception in batch of operations  " + e.getMessage());
+            }
+        }
+    }
+
 
     public void saveSharesInFolder(ArrayList<OCShare> shares, OCFile folder) {
         resetShareFlagsInFolder(folder);
 
     public void saveSharesInFolder(ArrayList<OCShare> shares, OCFile folder) {
         resetShareFlagsInFolder(folder);
@@ -1463,7 +1539,7 @@ public class FileDataStorageManager {
                 );
                 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
                 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
                 );
                 cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
                 cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
-                cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getIdRemoteShared());
+                cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getRemoteId());
                 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
                 // adding a new share resource
                 cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, mAccount.name);
 
                 // adding a new share resource
@@ -1484,9 +1560,8 @@ public class FileDataStorageManager {
                     + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
             String [] whereArgs = new String[]{ "", mAccount.name };
 
                     + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
             String [] whereArgs = new String[]{ "", mAccount.name };
 
-            // TODO Enable when "On Device" is recovered ?
-            Vector<OCFile> files = getFolderContent(folder /*, false*/);
-
+            Vector<OCFile> files = getFolderContent(folder, false);
+            
             for (OCFile file : files) {
                 whereArgs[0] = file.getRemotePath();
                 preparedOperations.add(
             for (OCFile file : files) {
                 whereArgs[0] = file.getRemotePath();
                 preparedOperations.add(
@@ -1558,9 +1633,11 @@ public class FileDataStorageManager {
     }
 
     public static void triggerMediaScan(String path) {
     }
 
     public static void triggerMediaScan(String path) {
-        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
-        intent.setData(Uri.fromFile(new File(path)));
-        MainApp.getAppContext().sendBroadcast(intent);
+        if (path != null) {
+            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+            intent.setData(Uri.fromFile(new File(path)));
+            MainApp.getAppContext().sendBroadcast(intent);
+        }
     }
 
     public void deleteFileInMediaScan(String path) {
     }
 
     public void deleteFileInMediaScan(String path) {
@@ -1860,6 +1937,8 @@ public class FileDataStorageManager {
 
         if (c.moveToFirst()) {
             capability = createCapabilityInstance(c);
 
         if (c.moveToFirst()) {
             capability = createCapabilityInstance(c);
+        } else {
+            capability = new OCCapability();    // return default with all UNKNOWN
         }
         c.close();
         return capability;
         }
         c.close();
         return capability;