Pārlūkot izejas kodu

Merge branch 'share_link__new_share' into share_link__new_share_menu

David A. Velasco 11 gadi atpakaļ
vecāks
revīzija
59513cd56d

+ 1 - 0
AndroidManifest.xml

@@ -151,6 +151,7 @@
             </intent-filter>
         </activity>
 
+        <service android:name=".services.OperationsService" />
         <service android:name=".files.services.FileDownloader" />
         <service android:name=".files.services.FileUploader" />
         <service android:name=".media.MediaService" />

+ 1 - 1
owncloud-android-library

@@ -1 +1 @@
-Subproject commit 974e55a2b95c652b794111254078b806f11fcf31
+Subproject commit 09b1c3c15aa2644635796c93ee918f8b0a20ff7c

+ 3 - 0
res/values/strings.xml

@@ -245,4 +245,7 @@
     <string name="failed_upload_retry_do_nothing_text">do nothing you are not online for instant upload</string>
 	<string name="failed_upload_failure_text">Failure Message: </string>
 	<string name="failed_upload_quota_exceeded_text">Please check your server configuration,maybe your quota is exceeded.</string>
+	
+	<string name="share_link_no_support_share_api">Sorry, sharing is not enabled on your server. Please contact your administrator.</string>
+	<string name="share_link_file_no_exist">Unable to share this file or folder. Please, make sure it exists</string>
 </resources>

+ 33 - 0
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -29,6 +29,7 @@ import com.owncloud.android.MainApp;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
 import com.owncloud.android.lib.operations.common.OCShare;
 import com.owncloud.android.lib.operations.common.ShareType;
+import com.owncloud.android.lib.utils.FileUtils;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.Log_OC;
 
@@ -1098,4 +1099,36 @@ public class FileDataStorageManager {
         }
         
     } 
+
+
+    public void saveSharesDB(ArrayList<OCShare> shares) {
+
+        if (shares.size() > 0) {
+            // Save share file
+            saveShares(shares);
+
+            ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
+
+            for (OCShare share : shares) {
+                // Get the path
+                String path = share.getPath();
+                if (share.isDirectory()) {
+                    path = path + FileUtils.PATH_SEPARATOR;
+                }           
+
+                // Update OCFile with data from share: ShareByLink  ¿and publicLink?
+                OCFile file = getFileByPath(path);
+                if (file != null) {
+                    if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
+                        file.setShareByLink(true);
+                        sharedFiles.add(file);
+                    }
+                } 
+            }
+            
+            if (sharedFiles.size() > 0) {
+                updateSharedFiles(sharedFiles);
+            }
+        }
+    }
 }

+ 34 - 6
src/com/owncloud/android/operations/CreateShareOperation.java

@@ -25,14 +25,18 @@ package com.owncloud.android.operations;
  */
 
 import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.network.OwnCloudClient;
-import com.owncloud.android.lib.operations.common.RemoteOperation;
+import com.owncloud.android.lib.operations.common.OCShare;
 import com.owncloud.android.lib.operations.common.RemoteOperationResult;
 import com.owncloud.android.lib.operations.common.ShareType;
 import com.owncloud.android.lib.operations.remote.CreateShareRemoteOperation;
+import com.owncloud.android.lib.utils.FileUtils;
+import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.utils.Log_OC;
+
+public class CreateShareOperation extends SyncOperation {
 
-public class CreateShareOperation extends RemoteOperation {
-    
     private static final String TAG = CreateShareOperation.class.getSimpleName();
 
     protected FileDataStorageManager mStorageManager;
@@ -43,7 +47,7 @@ public class CreateShareOperation extends RemoteOperation {
     private boolean mPublicUpload;
     private String mPassword;
     private int mPermissions;
-    
+
     /**
      * Constructor
      * @param path          Full path of the file/folder being shared. Mandatory argument
@@ -79,11 +83,35 @@ public class CreateShareOperation extends RemoteOperation {
         RemoteOperationResult result = operation.execute(client);
 
         if (result.isSuccess()) {
-            // TODO
-            // Update DB with the response
 
+            if (result.getData().size() > 0) {
+                OCShare share = (OCShare) result.getData().get(0);
+
+                // Update DB with the response
+                if (mPath.endsWith(FileUtils.PATH_SEPARATOR)) {
+                    share.setPath(mPath.substring(0, mPath.length()-1));
+                    share.setIsDirectory(true);
+                    
+                } else {
+                    share.setPath(mPath);
+                    share.setIsDirectory(false);
+                }
+                share.setPermissions(mPermissions);
+                
+                getStorageManager().saveShare(share);
+                
+                // Update OCFile with data from share: ShareByLink  and publicLink
+                OCFile file = getStorageManager().getFileByPath(mPath);
+                if (file!=null) {
+                    file.setPublicLink(share.getShareLink());
+                    getStorageManager().saveFile(file);
+                    Log_OC.d(TAG, "Public Link = " + file.getPublicLink());
+
+                }
+            }
         }
 
+
         return result;
     }
 

+ 79 - 0
src/com/owncloud/android/operations/GetSharesForFileOperation.java

@@ -0,0 +1,79 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+package com.owncloud.android.operations;
+
+import java.util.ArrayList;
+
+import com.owncloud.android.lib.network.OwnCloudClient;
+import com.owncloud.android.lib.operations.common.OCShare;
+import com.owncloud.android.lib.operations.common.RemoteOperationResult;
+import com.owncloud.android.lib.operations.remote.GetSharesForFileRemoteOperation;
+import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.utils.Log_OC;
+
+/**
+ * Provide a list shares for a specific file.  
+ * 
+ * @author masensio
+ *
+ */
+public class GetSharesForFileOperation extends SyncOperation {
+    
+    private static final String TAG = GetSharesForFileOperation.class.getSimpleName();
+    
+    private String mPath;
+    private boolean mReshares;
+    private boolean mSubfiles;
+
+    /**
+     * Constructor
+     * 
+     * @param path      Path to file or folder
+     * @param reshares  If set to ‘false’ (default), only shares from the current user are returned
+     *                  If set to ‘true’, all shares from the given file are returned
+     * @param subfiles  If set to ‘false’ (default), lists only the folder being shared
+     *                  If set to ‘true’, all shared files within the folder are returned.
+     */
+    public GetSharesForFileOperation(String path, boolean reshares, boolean subfiles) {
+        mPath = path;
+        mReshares = reshares;
+        mSubfiles = subfiles;
+    }
+
+    @Override
+    protected RemoteOperationResult run(OwnCloudClient client) {
+        GetSharesForFileRemoteOperation operation = new GetSharesForFileRemoteOperation(mPath, mReshares, mSubfiles);
+        RemoteOperationResult result = operation.execute(client);
+
+        if (result.isSuccess()) {
+
+            // Update DB with the response
+            Log_OC.d(TAG, "File = " + mPath + " Share list size  " + result.getData().size());
+            ArrayList<OCShare> shares = new ArrayList<OCShare>();
+            for(Object obj: result.getData()) {
+                shares.add((OCShare) obj);
+            }
+
+            getStorageManager().saveSharesDB(shares);
+        }
+
+        return result;
+    }
+
+}

+ 4 - 45
src/com/owncloud/android/operations/GetSharesOperation.java

@@ -19,15 +19,11 @@ package com.owncloud.android.operations;
 
 import java.util.ArrayList;
 
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.network.OwnCloudClient;
-import com.owncloud.android.lib.operations.common.RemoteOperation;
 import com.owncloud.android.lib.operations.common.RemoteOperationResult;
 import com.owncloud.android.lib.operations.common.OCShare;
-import com.owncloud.android.lib.operations.common.ShareType;
 import com.owncloud.android.lib.operations.remote.GetRemoteSharesOperation;
-import com.owncloud.android.lib.utils.FileUtils;
+import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.utils.Log_OC;
 
 /**
@@ -35,19 +31,13 @@ import com.owncloud.android.utils.Log_OC;
  * Save the data in Database
  * 
  * @author masensio
+ * @author David A. Velasco
  */
 
-public class GetSharesOperation extends RemoteOperation {
+public class GetSharesOperation extends SyncOperation {
 
     private static final String TAG = GetSharesOperation.class.getSimpleName();
 
-    protected FileDataStorageManager mStorageManager;
-
-
-    public GetSharesOperation(FileDataStorageManager storageManager) {
-        mStorageManager = storageManager;
-    }
-
     @Override
     protected RemoteOperationResult run(OwnCloudClient client) {
         GetRemoteSharesOperation operation = new GetRemoteSharesOperation();
@@ -62,41 +52,10 @@ public class GetSharesOperation extends RemoteOperation {
                 shares.add((OCShare) obj);
             }
 
-            saveSharesDB(shares);
+            getStorageManager().saveSharesDB(shares);
         }
 
         return result;
     }
 
-    private void saveSharesDB(ArrayList<OCShare> shares) {
-
-        if (shares.size() > 0) {
-            // Save share file
-            mStorageManager.saveShares(shares);
-
-            ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
-
-            for (OCShare share : shares) {
-                // Get the path
-                String path = share.getPath();
-                if (share.isDirectory()) {
-                    path = path + FileUtils.PATH_SEPARATOR;
-                }           
-
-                // Update OCFile with data from share: ShareByLink  ¿and publicLink?
-                OCFile file = mStorageManager.getFileByPath(path);
-                if (file != null) {
-                    if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
-                        file.setShareByLink(true);
-                        sharedFiles.add(file);
-                    }
-                } 
-            }
-            
-            if (sharedFiles.size() > 0) {
-                mStorageManager.updateSharedFiles(sharedFiles);
-            }
-        }
-    }
-
 }

+ 129 - 0
src/com/owncloud/android/operations/common/SyncOperation.java

@@ -0,0 +1,129 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2014 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.operations.common;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.lib.network.OwnCloudClient;
+import com.owncloud.android.lib.operations.common.OnRemoteOperationListener;
+import com.owncloud.android.lib.operations.common.RemoteOperation;
+import com.owncloud.android.lib.operations.common.RemoteOperationResult;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Handler;
+
+
+/**
+ * Operation which execution involves both interactions with an ownCloud server and
+ * with local data in the device.
+ * 
+ * Provides methods to execute the operation both synchronously or asynchronously.
+ * 
+ * @author David A. Velasco 
+ */
+public abstract class SyncOperation extends RemoteOperation {
+	
+    //private static final String TAG = SyncOperation.class.getSimpleName();
+
+    private FileDataStorageManager mStorageManager;
+    
+    public FileDataStorageManager getStorageManager() {
+        return mStorageManager;
+    }
+	
+
+    /**
+     * Synchronously executes the operation on the received ownCloud account.
+     * 
+     * Do not call this method from the main thread.
+     * 
+     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}. 
+     * 
+     * @param account   ownCloud account in remote ownCloud server to reach during the execution of the operation.
+     * @param context   Android context for the component calling the method.
+     * @return          Result of the operation.
+     */
+    public RemoteOperationResult execute(FileDataStorageManager storageManager, Context context) {
+        if (storageManager == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        }
+        if (storageManager.getAccount() == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account");
+        }
+        mStorageManager = storageManager;
+        return super.execute(mStorageManager.getAccount(), context);
+    }
+    
+	
+	/**
+	 * Synchronously executes the remote operation
+	 * 
+     * Do not call this method from the main thread.
+     * 
+	 * @param client	Client object to reach an ownCloud server during the execution of the operation.
+	 * @return			Result of the operation.
+	 */
+	public RemoteOperationResult execute(OwnCloudClient client, FileDataStorageManager storageManager) {
+        if (storageManager == null)
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        mStorageManager = storageManager;
+		return super.execute(client);
+	}
+
+	
+    /**
+     * Asynchronously executes the remote operation
+     * 
+     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(OwnCloudClient)}. 
+     * 
+     * @param account           ownCloud account in remote ownCloud server to reach during the execution of the operation.
+     * @param context           Android context for the component calling the method.
+     * @param listener          Listener to be notified about the execution of the operation.
+     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
+     * @return                  Thread were the remote operation is executed.
+     */
+    public Thread execute(FileDataStorageManager storageManager, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
+        if (storageManager == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        }
+        if (storageManager.getAccount() == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a storage manager for a NULL account");
+        }
+        mStorageManager = storageManager;
+        return super.execute(storageManager.getAccount(), context, listener, listenerHandler, callerActivity);
+    }
+
+    
+	/**
+	 * Asynchronously executes the remote operation
+	 * 
+	 * @param client			Client object to reach an ownCloud server during the execution of the operation.
+	 * @param listener			Listener to be notified about the execution of the operation.
+	 * @param listenerHandler	Handler associated to the thread where the methods of the listener objects must be called.
+	 * @return					Thread were the remote operation is executed.
+	 */
+	public Thread execute(OwnCloudClient client, FileDataStorageManager storageManager, OnRemoteOperationListener listener, Handler listenerHandler) {
+        if (storageManager == null) {
+            throw new IllegalArgumentException("Trying to execute a sync operation with a NULL storage manager");
+        }
+        mStorageManager = storageManager;
+        return super.execute(client, listener, listenerHandler);
+	}
+
+	
+}

+ 287 - 0
src/com/owncloud/android/services/OperationsService.java

@@ -0,0 +1,287 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.services;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+
+import com.owncloud.android.lib.network.OwnCloudClientFactory;
+import com.owncloud.android.lib.network.OwnCloudClient;
+import com.owncloud.android.operations.GetSharesOperation;
+import com.owncloud.android.operations.common.SyncOperation;
+import com.owncloud.android.lib.operations.common.RemoteOperation;
+import com.owncloud.android.lib.operations.common.RemoteOperationResult;
+import com.owncloud.android.utils.Log_OC;
+
+import android.accounts.Account;
+import android.accounts.AccountsException;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Pair;
+
+public class OperationsService extends Service {
+    
+    private static final String TAG = OperationsService.class.getSimpleName();
+    
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    public static final String EXTRA_SERVER_URL = "SERVER_URL";
+    public static final String EXTRA_RESULT = "RESULT";    
+    
+    public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED";
+    public static final String ACTION_OPERATION_FINISHED = OperationsService.class.getName() + ".OPERATION_FINISHED";
+
+    private ConcurrentLinkedQueue<Pair<Target, RemoteOperation>> mPendingOperations = new ConcurrentLinkedQueue<Pair<Target, RemoteOperation>>();
+    
+    private static class Target {
+        public Uri mServerUrl = null;
+        public Account mAccount = null;
+        public Target(Account account, Uri serverUrl) {
+            mAccount = account;
+            mServerUrl = serverUrl;
+        }
+    }
+
+    private Looper mServiceLooper;
+    private ServiceHandler mServiceHandler;
+    private IBinder mBinder;
+    private OwnCloudClient mOwnCloudClient = null;
+    private Target mLastTarget = null;
+    private FileDataStorageManager mStorageManager;
+    private RemoteOperation mCurrentOperation = null;
+    
+    
+    /**
+     * Service initialization
+     */
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        HandlerThread thread = new HandlerThread("Operations service thread", Process.THREAD_PRIORITY_BACKGROUND);
+        thread.start();
+        mServiceLooper = thread.getLooper();
+        mServiceHandler = new ServiceHandler(mServiceLooper, this);
+        mBinder = new OperationsServiceBinder();
+    }
+
+    /**
+     * Entry point to add a new operation to the queue of operations.
+     * 
+     * New operations are added calling to startService(), resulting in a call to this method. 
+     * This ensures the service will keep on working although the caller activity goes away.
+     * 
+     * IMPORTANT: the only operations performed here right now is {@link GetSharedFilesOperation}. The class
+     * is taking advantage of it due to time constraints.
+     */
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_SERVER_URL)) {
+            Log_OC.e(TAG, "Not enough information provided in intent");
+            return START_NOT_STICKY;
+        }
+        try {
+            Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
+            String serverUrl = intent.getStringExtra(EXTRA_SERVER_URL);
+            Target target = new Target(account, (serverUrl == null) ? null : Uri.parse(serverUrl));
+            GetSharesOperation operation = new GetSharesOperation();
+            mPendingOperations.add(new Pair<Target , RemoteOperation>(target, operation));
+            sendBroadcastNewOperation(target, operation);
+            
+            Message msg = mServiceHandler.obtainMessage();
+            msg.arg1 = startId;
+            mServiceHandler.sendMessage(msg);
+            
+        } catch (IllegalArgumentException e) {
+            Log_OC.e(TAG, "Bad information provided in intent: " + e.getMessage());
+            return START_NOT_STICKY;
+        }
+        
+        return START_NOT_STICKY;
+    }
+
+    
+    /**
+     * Provides a binder object that clients can use to perform actions on the queue of operations, 
+     * except the addition of new operations. 
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    
+    /**
+     * Called when ALL the bound clients were unbound.
+     */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        //((OperationsServiceBinder)mBinder).clearListeners();
+        return false;   // not accepting rebinding (default behaviour)
+    }
+
+    
+    /**
+     *  Binder to let client components to perform actions on the queue of operations.
+     * 
+     *  It provides by itself the available operations.
+     */
+    public class OperationsServiceBinder extends Binder {
+        // TODO
+    }
+    
+    
+    /** 
+     * Operations worker. Performs the pending operations in the order they were requested. 
+     * 
+     * Created with the Looper of a new thread, started in {@link OperationsService#onCreate()}. 
+     */
+    private static class ServiceHandler extends Handler {
+        // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
+        OperationsService mService;
+        public ServiceHandler(Looper looper, OperationsService service) {
+            super(looper);
+            if (service == null) {
+                throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
+            }
+            mService = service;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            mService.nextOperation();
+            mService.stopSelf(msg.arg1);
+        }
+    }
+    
+
+    /**
+     * Performs the next operation in the queue
+     */
+    private void nextOperation() {
+        
+        Pair<Target, RemoteOperation> next = null;
+        synchronized(mPendingOperations) {
+            next = mPendingOperations.peek();
+        }
+        
+        if (next != null) {
+            
+            mCurrentOperation = next.second;
+            RemoteOperationResult result = null;
+            try {
+                /// prepare client object to send the request to the ownCloud server
+                if (mLastTarget == null || !mLastTarget.equals(next.first)) {
+                    mLastTarget = next.first;
+                    if (mLastTarget.mAccount != null) {
+                        mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient(mLastTarget.mAccount, getApplicationContext());
+                        mStorageManager = new FileDataStorageManager(mLastTarget.mAccount, getContentResolver());
+                    } else {
+                        mOwnCloudClient = OwnCloudClientFactory.createOwnCloudClient(mLastTarget.mServerUrl, getApplicationContext(), true);    // this is not good enough
+                        mStorageManager = null;
+                    }
+                }
+
+                /// perform the operation
+                if (mCurrentOperation instanceof SyncOperation) {
+                    result = ((SyncOperation)mCurrentOperation).execute(mOwnCloudClient, mStorageManager);
+                } else {
+                    result = mCurrentOperation.execute(mOwnCloudClient);
+                }
+            
+            } catch (AccountsException e) {
+                if (mLastTarget.mAccount == null) {
+                    Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e);
+                } else {
+                    Log_OC.e(TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e);
+                }
+                result = new RemoteOperationResult(e);
+                
+            } catch (IOException e) {
+                if (mLastTarget.mAccount == null) {
+                    Log_OC.e(TAG, "Error while trying to get autorization for a NULL account", e);
+                } else {
+                    Log_OC.e(TAG, "Error while trying to get autorization for " + mLastTarget.mAccount.name, e);
+                }
+                result = new RemoteOperationResult(e);
+                
+            } finally {
+                synchronized(mPendingOperations) {
+                    mPendingOperations.poll();
+                }
+            }
+            
+            sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result);
+        }
+    }
+
+
+    /**
+     * Sends a LOCAL broadcast when a new operation is added to the queue.
+     * 
+     * Local broadcasts are only delivered to activities in the same process.
+     * 
+     * @param target            Account or URL pointing to an OC server.
+     * @param operation         Added operation.
+     */
+    private void sendBroadcastNewOperation(Target target, RemoteOperation operation) {
+        Intent intent = new Intent(ACTION_OPERATION_ADDED);
+        if (target.mAccount != null) {
+            intent.putExtra(EXTRA_ACCOUNT, target.mAccount);    
+        } else {
+            intent.putExtra(EXTRA_SERVER_URL, target.mServerUrl);    
+        }
+        LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
+        lbm.sendBroadcast(intent);
+    }
+
+    
+    // TODO - maybe add a notification for real start of operations
+    
+    /**
+     * Sends a LOCAL broadcast when an operations finishes in order to the interested activities can update their view
+     * 
+     * Local broadcasts are only delivered to activities in the same process.
+     * 
+     * @param target            Account or URL pointing to an OC server.
+     * @param operation         Finished operation.
+     * @param result            Result of the operation.
+     */
+    private void sendBroadcastOperationFinished(Target target, RemoteOperation operation, RemoteOperationResult result) {
+        Intent intent = new Intent(ACTION_OPERATION_FINISHED);
+        intent.putExtra(EXTRA_RESULT, result);
+        if (target.mAccount != null) {
+            intent.putExtra(EXTRA_ACCOUNT, target.mAccount);    
+        } else {
+            intent.putExtra(EXTRA_SERVER_URL, target.mServerUrl);    
+        }
+        LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
+        lbm.sendBroadcast(intent);
+    }
+    
+    
+}

+ 36 - 24
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -35,6 +35,7 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.webkit.MimeTypeMap;
+import android.widget.Toast;
 
 import com.actionbarsherlock.app.SherlockFragmentActivity;
 import com.owncloud.android.MainApp;
@@ -370,36 +371,47 @@ public abstract class FileActivity extends SherlockFragmentActivity {
     */
     
     public void shareFileWithLink(OCFile file) {
-        if (file != null) {
-            
-            //CreateShareOperation createShare = new CreateShareOperation(file.getRemotePath(), ShareType.PUBLIC_LINK, "", false, "", 1);
-            //createShare.execute(getAccount(), this, this, mHandler, this);
-            
-            String link = "https://fake.url.lolo";
-            Intent chooserIntent = null;
-            List<Intent> targetedShareIntents = new ArrayList<Intent>();
-            List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(createShareWithLinkIntent(link), PackageManager.MATCH_DEFAULT_ONLY);
-            String myPackageName = getPackageName();
-            if (!resInfo.isEmpty()) {
-                for (ResolveInfo info : resInfo) {
-                    if (!info.activityInfo.packageName.equalsIgnoreCase(myPackageName)) {
-                        Intent targetedShare = createTargetedShare(link, info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
-                        targetedShareIntents.add(targetedShare);
+        if (isSharedSupported()) {
+            if (file != null) {
+                
+                // Create the Share
+                //CreateShareOperation createShare = new CreateShareOperation(file.getRemotePath(), ShareType.PUBLIC_LINK, "", false, "", 1);
+                //createShare.execute(getStorageManager(), this, this, mHandler, this);
+                        
+                // TODO
+                // Get the link --> when the operation is finished
+                        
+                String link = "https://fake.url.lolo";
+                Intent chooserIntent = null;
+                List<Intent> targetedShareIntents = new ArrayList<Intent>();
+                List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(createShareWithLinkIntent(link), PackageManager.MATCH_DEFAULT_ONLY);
+                String myPackageName = getPackageName();
+                if (!resInfo.isEmpty()) {
+                    for (ResolveInfo info : resInfo) {
+                        if (!info.activityInfo.packageName.equalsIgnoreCase(myPackageName)) {
+                            Intent targetedShare = createTargetedShare(link, info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
+                            targetedShareIntents.add(targetedShare);
+                        }
                     }
                 }
-            }
-            if (targetedShareIntents.size() > 0) {
-                Intent firstTargeted = targetedShareIntents.remove(0);
-                chooserIntent = Intent.createChooser(firstTargeted, getString(R.string.action_share_file));
-                chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[] {}));
+                if (targetedShareIntents.size() > 0) {
+                    Intent firstTargeted = targetedShareIntents.remove(0);
+                    chooserIntent = Intent.createChooser(firstTargeted, getString(R.string.action_share_file));
+                    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[] {}));
+                } else {
+                    // to show standard message
+                    chooserIntent = Intent.createChooser(null, getString(R.string.action_share_file));
+                }
+                startActivity(chooserIntent);
+                
             } else {
-                // to show standard message
-                chooserIntent = Intent.createChooser(null, getString(R.string.action_share_file));
+                Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
             }
-            startActivity(chooserIntent);
             
         } else {
-            Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
+            // Show a Message
+            Toast t = Toast.makeText(this, getString(R.string.share_link_no_support_share_api), Toast.LENGTH_LONG);
+            t.show();
         }
     }
     

+ 67 - 32
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -45,6 +45,7 @@ import android.provider.MediaStore;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
+import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -69,17 +70,16 @@ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 import com.owncloud.android.operations.CreateFolderOperation;
 
-import com.owncloud.android.operations.GetSharesOperation;
-
 import com.owncloud.android.lib.operations.common.OnRemoteOperationListener;
 import com.owncloud.android.lib.operations.common.RemoteOperation;
 import com.owncloud.android.lib.operations.common.RemoteOperationResult;
 import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode;
-
+import com.owncloud.android.operations.CreateShareOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
+import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.syncadapter.FileSyncService;
 import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
@@ -114,6 +114,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     private SyncBroadcastReceiver mSyncBroadcastReceiver;
     private UploadFinishReceiver mUploadFinishReceiver;
     private DownloadFinishReceiver mDownloadFinishReceiver;
+    private OperationsServiceReceiver mOperationsServiceReceiver;
     private FileDownloaderBinder mDownloaderBinder = null;
     private FileUploaderBinder mUploaderBinder = null;
     private ServiceConnection mDownloadConnection = null, mUploadConnection = null;
@@ -703,6 +704,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
         downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage());
         mDownloadFinishReceiver = new DownloadFinishReceiver();
         registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
+        
+        // Listen for messages from the OperationsService
+        IntentFilter operationsIntentFilter = new IntentFilter(OperationsService.ACTION_OPERATION_ADDED);
+        operationsIntentFilter.addAction(OperationsService.ACTION_OPERATION_FINISHED);
+        mOperationsServiceReceiver = new OperationsServiceReceiver();
+        LocalBroadcastManager.getInstance(this).registerReceiver(mOperationsServiceReceiver, operationsIntentFilter);
     
         Log_OC.d(TAG, "onResume() end");
     }
@@ -724,7 +731,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             unregisterReceiver(mDownloadFinishReceiver);
             mDownloadFinishReceiver = null;
         }
-
+        if (mOperationsServiceReceiver != null) {
+            LocalBroadcastManager.getInstance(this).unregisterReceiver(mOperationsServiceReceiver);
+            mOperationsServiceReceiver = null;
+        }
         Log_OC.d(TAG, "onPause() end");
     }
 
@@ -1031,6 +1041,45 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             return (accountName != null && getAccount() != null && accountName.equals(getAccount().name));
         }
     }
+    
+    
+    /**
+     * Class waiting for broadcast events from the {@link OperationsService}.
+     * 
+     * Updates the list of files when a get for shares is finished; at this moment the refresh of shares is the only
+     * operation performed in {@link OperationsService}.
+     * 
+     * In the future will handle the progress or finalization of all the operations performed in {@link OperationsService}, 
+     * probably all the operations associated to the app model. 
+     */
+    private class OperationsServiceReceiver extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (OperationsService.ACTION_OPERATION_ADDED.equals(intent.getAction())) {
+                
+            } else if (OperationsService.ACTION_OPERATION_FINISHED.equals(intent.getAction())) {
+                mRefreshSharesInProgress = false;
+                
+                Account account = intent.getParcelableExtra(OperationsService.EXTRA_ACCOUNT);
+                RemoteOperationResult getSharesResult = (RemoteOperationResult)intent.getSerializableExtra(OperationsService.EXTRA_RESULT);
+                if (getAccount() != null && account.name.equals(getAccount().name)
+                        && mStorageManager != null
+                        ) {
+                    refeshListOfFilesFragment();
+                }
+                if ((getSharesResult != null) &&
+                        RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(getSharesResult.getCode())) {
+                    mLastSslUntrustedServerResult = getSharesResult;
+                    showDialog(DIALOG_SSL_VALIDATOR); 
+                }
+
+                setSupportProgressBarIndeterminateVisibility(mRefreshSharesInProgress || mSyncInProgress);
+            }
+            
+        }
+            
+    }
 
 
     /**
@@ -1295,27 +1344,23 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
         } else if (operation instanceof CreateFolderOperation) {
             onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
-            
-        } else if (operation instanceof GetSharesOperation) {
-            onGetSharesOperationFinish((GetSharesOperation) operation, result);
+        
+        } else if (operation instanceof CreateShareOperation) {
+            onCreateShareOperation((CreateShareOperation) operation, result);
         }
+        
     }
 
 
-    /** Updates the data about shared files
-     * 
-     * @param operation     Get Shared Files
-     * @param result        Result of the operation
-     */
-    private void onGetSharesOperationFinish(GetSharesOperation operation, RemoteOperationResult result) {
-        // Refresh the filelist with the information
-        refeshListOfFilesFragment();  
+    private void onCreateShareOperation(CreateShareOperation operation, RemoteOperationResult result) {
+        if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+            // Show a Message
+            Toast t = Toast.makeText(this, getString(R.string.share_link_file_no_exist), Toast.LENGTH_LONG);
+            t.show();
+        }
         
-        mRefreshSharesInProgress = false;
+        refeshListOfFilesFragment();
         
-        if (!mSyncInProgress) {
-            setSupportProgressBarIndeterminateVisibility(false);
-        }
     }
 
     /**
@@ -1529,23 +1574,13 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
     
     private void startGetShares() {
         // Get shared files/folders
-        RemoteOperation getShares = new GetSharesOperation(mStorageManager);
-        getShares.execute(getAccount(), this, this, mHandler, this);
+        Intent intent = new Intent(this, OperationsService.class);
+        intent.putExtra(OperationsService.EXTRA_ACCOUNT, getAccount());
+        startService(intent);
         
         mRefreshSharesInProgress = true;
         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);
-//          }
-//        }
-//      }
 }

+ 0 - 3
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -55,9 +55,6 @@ import com.owncloud.android.lib.operations.common.OnRemoteOperationListener;
 import com.owncloud.android.lib.operations.common.RemoteOperation;
 import com.owncloud.android.lib.operations.common.RemoteOperationResult;
 import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode;
-import com.owncloud.android.lib.operations.common.ShareType;
-import com.owncloud.android.lib.operations.remote.CreateShareRemoteOperation;
-import com.owncloud.android.operations.CreateShareOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;