X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/2623e9c1957e95166e99adc81481f91136ac4453..5dc43aab3cc1243f9989dd6a0c7dd3350c3f709b:/src/com/owncloud/android/operations/RemoteOperation.java diff --git a/src/com/owncloud/android/operations/RemoteOperation.java b/src/com/owncloud/android/operations/RemoteOperation.java index 1564f193..711a72b0 100644 --- a/src/com/owncloud/android/operations/RemoteOperation.java +++ b/src/com/owncloud/android/operations/RemoteOperation.java @@ -2,9 +2,8 @@ * 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 as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. + * 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 @@ -17,6 +16,21 @@ */ package com.owncloud.android.operations; +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.network.BearerCredentials; +import com.owncloud.android.network.OwnCloudClientUtils; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountsException; +import android.app.Activity; +import android.content.Context; import android.os.Handler; import eu.alefzero.webdav.WebdavClient; @@ -30,7 +44,15 @@ import eu.alefzero.webdav.WebdavClient; */ public abstract class RemoteOperation implements Runnable { - /** Object to interact with the ownCloud server */ + private static final String TAG = RemoteOperation.class.getSimpleName(); + + /** ownCloud account in the remote ownCloud server to operate */ + private Account mAccount = null; + + /** Android Application context */ + private Context mContext = null; + + /** Object to interact with the remote server */ private WebdavClient mClient = null; /** Callback object to notify about the execution of the remote operation */ @@ -39,16 +61,49 @@ public abstract class RemoteOperation implements Runnable { /** Handler to the thread where mListener methods will be called */ private Handler mListenerHandler = null; + /** Activity */ + private Activity mCallerActivity; + /** * Abstract method to implement the operation in derived classes. */ protected abstract RemoteOperationResult run(WebdavClient client); + + /** + * Synchronously executes the remote 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(WebdavClient)}. + * + * @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 final RemoteOperationResult execute(Account account, Context context) { + if (account == null) + throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account"); + if (context == null) + throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context"); + mAccount = account; + mContext = context.getApplicationContext(); + try { + mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext); + } catch (Exception e) { + Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); + return new RemoteOperationResult(e); + } + return run(mClient); + } + /** * 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. */ @@ -60,6 +115,43 @@ public abstract class RemoteOperation implements Runnable { } + /** + * Asynchronously executes the remote operation + * + * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}. + * + * @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 final Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) { + if (account == null) + throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account"); + if (context == null) + throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context"); + mAccount = account; + mContext = context.getApplicationContext(); + 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); + runnerThread.start(); + return runnerThread; + } + + /** * Asynchronously executes the remote operation * @@ -116,20 +208,74 @@ public abstract class RemoteOperation implements Runnable { * Asynchronous execution of the operation * started by {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}, * and result posting. + * + * TODO refactor && clean the code; now it's a mess */ @Override public final void run() { - final RemoteOperationResult result = execute(mClient); + RemoteOperationResult result = null; + boolean repeat = false; + do { + try{ + if (mClient == null) { + if (mAccount != null && mContext != null) { + if (mCallerActivity != null) { + mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext, mCallerActivity); + } else { + mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext); + } + } else { + throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account"); + } + } + + } catch (IOException e) { + Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e)); + result = new RemoteOperationResult(e); + + } catch (AccountsException e) { + Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); + result = new RemoteOperationResult(e); + } + if (result == null) + result = run(mClient); + + repeat = false; + if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() && result.getCode() == ResultCode.UNAUTHORIZED) { + /// fail due to lack of authorization in an operation performed in foreground + AccountManager am = AccountManager.get(mContext); + Credentials cred = mClient.getCredentials(); + if (cred instanceof BearerCredentials) { + am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ((BearerCredentials)cred).getAccessToken()); + } else { + am.clearPassword(mAccount); + } + mClient = null; + repeat = true; // when repeated, the creation of a new OwnCloudClient after erasing the saved credentials will trigger the login activity + result = null; + } + } while (repeat); + + final RemoteOperationResult resultToSend = result; if (mListenerHandler != null && mListener != null) { mListenerHandler.post(new Runnable() { @Override public void run() { - mListener.onRemoteOperationFinish(RemoteOperation.this, result); + mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend); } }); } } - - + + + /** + * Returns the current client instance to access the remote server. + * + * @return Current client instance to access the remote server. + */ + public final WebdavClient getClient() { + return mClient; + } + }