Merge branch 'share_link_show_shared_files' into share_link__new_share

This commit is contained in:
masensio 2014-01-30 18:54:54 +01:00
commit c550c8701b
6 changed files with 479 additions and 49 deletions

View file

@ -149,6 +149,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 @@
Subproject commit afb4ae1c2e15dfc3b3f9a9861b75d375e38f2805
Subproject commit 8ab453d630458fc6cdcd1bf68493d82365f1c6d3

View file

@ -19,15 +19,14 @@ 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 +34,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();
@ -72,7 +65,7 @@ public class GetSharesOperation extends RemoteOperation {
if (shares.size() > 0) {
// Save share file
mStorageManager.saveShares(shares);
getStorageManager().saveShares(shares);
ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
@ -84,7 +77,7 @@ public class GetSharesOperation extends RemoteOperation {
}
// Update OCFile with data from share: ShareByLink ¿and publicLink?
OCFile file = mStorageManager.getFileByPath(path);
OCFile file = getStorageManager().getFileByPath(path);
if (file != null) {
if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
file.setShareByLink(true);
@ -94,7 +87,7 @@ public class GetSharesOperation extends RemoteOperation {
}
if (sharedFiles.size() > 0) {
mStorageManager.updateSharedFiles(sharedFiles);
getStorageManager().updateSharedFiles(sharedFiles);
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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,8 +70,6 @@ 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;
@ -82,6 +81,7 @@ 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;
@ -116,6 +116,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;
@ -706,6 +707,12 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
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");
}
@ -726,7 +733,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");
}
@ -1035,6 +1045,45 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
}
/**
* 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);
}
}
}
/**
* {@inheritDoc}
*/
@ -1297,29 +1346,10 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
} else if (operation instanceof CreateFolderOperation) {
onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
} else if (operation instanceof GetSharesOperation) {
onGetSharesOperationFinish((GetSharesOperation) 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();
mRefreshSharesInProgress = false;
if (!mSyncInProgress) {
setSupportProgressBarIndeterminateVisibility(false);
}
}
/**
* Updates the view associated to the activity after the finish of an operation trying to remove a
* file.
@ -1531,8 +1561,9 @@ 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);
@ -1546,15 +1577,4 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
}
// 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);
// }
// }
// }
}