mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-31 10:27:45 +00:00 
			
		
		
		
	Invalidate the client token when access token expires and try the last operation [WIP]
This commit is contained in:
		
							parent
							
								
									fe947194c5
								
							
						
					
					
						commit
						a1b1c2f9ed
					
				| @ -1,5 +1,5 @@ | |||||||
| /* ownCloud Android Library is available under MIT license | /* ownCloud Android Library is available under MIT license | ||||||
|  *   Copyright (C) 2016 ownCloud GmbH. |  *   Copyright (C) 2017 ownCloud GmbH. | ||||||
|  *    |  *    | ||||||
|  *   Permission is hereby granted, free of charge, to any person obtaining a copy |  *   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  *   of this software and associated documentation files (the "Software"), to deal |  *   of this software and associated documentation files (the "Software"), to deal | ||||||
| @ -49,40 +49,57 @@ import java.io.IOException; | |||||||
|  * Provides methods to execute the operation both synchronously or asynchronously. |  * Provides methods to execute the operation both synchronously or asynchronously. | ||||||
|  * |  * | ||||||
|  * @author David A. Velasco |  * @author David A. Velasco | ||||||
|  |  * @author David González Verdugo | ||||||
|  */ |  */ | ||||||
| public abstract class RemoteOperation implements Runnable { | public abstract class RemoteOperation implements Runnable { | ||||||
| 
 | 
 | ||||||
|     private static final String TAG = RemoteOperation.class.getSimpleName(); |     private static final String TAG = RemoteOperation.class.getSimpleName(); | ||||||
| 
 | 
 | ||||||
|     /** OCS API header name */ |     /** | ||||||
|  |      * OCS API header name | ||||||
|  |      */ | ||||||
|     public static final String OCS_API_HEADER = "OCS-APIREQUEST"; |     public static final String OCS_API_HEADER = "OCS-APIREQUEST"; | ||||||
| 
 | 
 | ||||||
|     /** OCS API header value */ |     /** | ||||||
|  |      * OCS API header value | ||||||
|  |      */ | ||||||
|     public static final String OCS_API_HEADER_VALUE = "true"; |     public static final String OCS_API_HEADER_VALUE = "true"; | ||||||
| 
 | 
 | ||||||
|     /** ownCloud account in the remote ownCloud server to operate */ |     /** | ||||||
|  |      * ownCloud account in the remote ownCloud server to operate | ||||||
|  |      */ | ||||||
|     private Account mAccount = null; |     private Account mAccount = null; | ||||||
| 
 | 
 | ||||||
|     /** Android Application context */ |     /** | ||||||
|  |      * Android Application context | ||||||
|  |      */ | ||||||
|     private Context mContext = null; |     private Context mContext = null; | ||||||
| 
 | 
 | ||||||
| 	/** Object to interact with the remote server */ |     /** | ||||||
| 	private OwnCloudClient mClient = null; |      * Object to interact with the remote server | ||||||
|  |      */ | ||||||
|  |     private OwnCloudClient mClient = null; | ||||||
| 
 | 
 | ||||||
| 	/** Callback object to notify about the execution of the remote operation */ |     /** | ||||||
| 	private OnRemoteOperationListener mListener = null; |      * Callback object to notify about the execution of the remote operation | ||||||
|  |      */ | ||||||
|  |     private OnRemoteOperationListener mListener = null; | ||||||
| 
 | 
 | ||||||
| 	/** Handler to the thread where mListener methods will be called */ |     /** | ||||||
| 	private Handler mListenerHandler = null; |      * Handler to the thread where mListener methods will be called | ||||||
|  |      */ | ||||||
|  |     private Handler mListenerHandler = null; | ||||||
| 
 | 
 | ||||||
| 	/** Activity */ |     /** | ||||||
|  |      * Activity | ||||||
|  |      */ | ||||||
|     private Activity mCallerActivity; |     private Activity mCallerActivity; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/** |     /** | ||||||
| 	 *  Abstract method to implement the operation in derived classes. |      * Abstract method to implement the operation in derived classes. | ||||||
| 	 */ |      */ | ||||||
| 	protected abstract RemoteOperationResult run(OwnCloudClient client); |     protected abstract RemoteOperationResult run(OwnCloudClient client); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -93,10 +110,10 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|      * This method should be used whenever an ownCloud account is available, instead of |      * This method should be used whenever an ownCloud account is available, instead of | ||||||
|      * {@link #execute(OwnCloudClient)}. |      * {@link #execute(OwnCloudClient)}. | ||||||
|      * |      * | ||||||
|      * @param account   ownCloud account in remote ownCloud server to reach during the |      * @param account ownCloud account in remote ownCloud server to reach during the | ||||||
|      *                  execution of the operation. |      *                execution of the operation. | ||||||
|      * @param context   Android context for the component calling the method. |      * @param context Android context for the component calling the method. | ||||||
|      * @return          Result of the operation. |      * @return Result of the operation. | ||||||
|      */ |      */ | ||||||
|     public RemoteOperationResult execute(Account account, Context context) { |     public RemoteOperationResult execute(Account account, Context context) { | ||||||
|         if (account == null) |         if (account == null) | ||||||
| @ -108,9 +125,9 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|         mAccount = account; |         mAccount = account; | ||||||
|         mContext = context.getApplicationContext(); |         mContext = context.getApplicationContext(); | ||||||
|         try { |         try { | ||||||
|         	OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); |             OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||||
|             mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). |             mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). | ||||||
|             		getClientFor(ocAccount, mContext); |                     getClientFor(ocAccount, mContext); | ||||||
|         } catch (Exception e) { |         } catch (Exception e) { | ||||||
|             Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); |             Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e); | ||||||
|             return new RemoteOperationResult(e); |             return new RemoteOperationResult(e); | ||||||
| @ -119,22 +136,22 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/** |     /** | ||||||
| 	 * Synchronously executes the remote operation |      * Synchronously executes the remote operation | ||||||
| 	 *  |      * | ||||||
|      * Do not call this method from the main thread. |      * Do not call this method from the main thread. | ||||||
|      * |      * | ||||||
| 	 * @param client	Client object to reach an ownCloud server during the execution of |      * @param client Client object to reach an ownCloud server during the execution of | ||||||
|      *                  the operation. |      *               the operation. | ||||||
| 	 * @return			Result of the operation. |      * @return Result of the operation. | ||||||
| 	 */ |      */ | ||||||
| 	public RemoteOperationResult execute(OwnCloudClient client) { |     public RemoteOperationResult execute(OwnCloudClient client) { | ||||||
| 		if (client == null) |         if (client == null) | ||||||
| 			throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " + |             throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " + | ||||||
|                     "OwnCloudClient"); |                     "OwnCloudClient"); | ||||||
| 		mClient = client; |         mClient = client; | ||||||
| 		return run(client); |         return run(client); | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -143,19 +160,18 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|      * This method should be used whenever an ownCloud account is available, instead of |      * This method should be used whenever an ownCloud account is available, instead of | ||||||
|      * {@link #execute(OwnCloudClient)}. |      * {@link #execute(OwnCloudClient)}. | ||||||
|      * |      * | ||||||
|      * @deprecated 	This method will be removed in version 1.0. |      * @param account         ownCloud account in remote ownCloud server to reach during | ||||||
|      *  			Use {@link #execute(Account, Context, OnRemoteOperationListener, |      *                        the execution of the operation. | ||||||
|      *  			Handler)} instead. |      * @param context         Android context for the component calling the method. | ||||||
|      *  |      * @param listener        Listener to be notified about the execution of the operation. | ||||||
|      * @param account           ownCloud account in remote ownCloud server to reach during |      * @param listenerHandler Handler associated to the thread where the methods of the listener | ||||||
|      *                          the execution of the operation. |      *                        objects must be called. | ||||||
|      * @param context           Android context for the component calling the method. |      * @return Thread were the remote operation is executed. | ||||||
|      * @param listener          Listener to be notified about the execution of the operation. |      * @deprecated This method will be removed in version 1.0. | ||||||
|      * @param listenerHandler   Handler associated to the thread where the methods of the listener |      * Use {@link #execute(Account, Context, OnRemoteOperationListener, | ||||||
|      *                          objects must be called. |      * Handler)} instead. | ||||||
|      * @return                  Thread were the remote operation is executed. |  | ||||||
|      */ |      */ | ||||||
| 	@Deprecated |     @Deprecated | ||||||
|     public Thread execute(Account account, Context context, OnRemoteOperationListener listener, |     public Thread execute(Account account, Context context, OnRemoteOperationListener listener, | ||||||
|                           Handler listenerHandler, Activity callerActivity) { |                           Handler listenerHandler, Activity callerActivity) { | ||||||
|         if (account == null) |         if (account == null) | ||||||
| @ -168,7 +184,7 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|         mContext = context.getApplicationContext(); |         mContext = context.getApplicationContext(); | ||||||
|         mCallerActivity = callerActivity; |         mCallerActivity = callerActivity; | ||||||
|         mClient = null;     // the client instance will be created from mAccount |         mClient = null;     // the client instance will be created from mAccount | ||||||
|                             // and mContext in the runnerThread to create below |         // and mContext in the runnerThread to create below | ||||||
|         mListener = listener; |         mListener = listener; | ||||||
| 
 | 
 | ||||||
|         mListenerHandler = listenerHandler; |         mListenerHandler = listenerHandler; | ||||||
| @ -185,13 +201,13 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|      * This method should be used whenever an ownCloud account is available, |      * This method should be used whenever an ownCloud account is available, | ||||||
|      * instead of {@link #execute(OwnCloudClient, OnRemoteOperationListener, Handler))}. |      * instead of {@link #execute(OwnCloudClient, OnRemoteOperationListener, Handler))}. | ||||||
|      * |      * | ||||||
|      * @param account           ownCloud account in remote ownCloud server to reach during the  |      * @param account         ownCloud account in remote ownCloud server to reach during the | ||||||
|      * 							execution of the operation. |      *                        execution of the operation. | ||||||
|      * @param context           Android context for the component calling the method. |      * @param context         Android context for the component calling the method. | ||||||
|      * @param listener          Listener to be notified about 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  |      * @param listenerHandler Handler associated to the thread where the methods of the listener | ||||||
|      * 							objects must be called. |      *                        objects must be called. | ||||||
|      * @return                  Thread were the remote operation is executed. |      * @return Thread were the remote operation is executed. | ||||||
|      */ |      */ | ||||||
|     public Thread execute(Account account, Context context, |     public Thread execute(Account account, Context context, | ||||||
|                           OnRemoteOperationListener listener, Handler listenerHandler) { |                           OnRemoteOperationListener listener, Handler listenerHandler) { | ||||||
| @ -206,7 +222,7 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|         mContext = context.getApplicationContext(); |         mContext = context.getApplicationContext(); | ||||||
|         mCallerActivity = null; |         mCallerActivity = null; | ||||||
|         mClient = null;     // the client instance will be created from |         mClient = null;     // the client instance will be created from | ||||||
|                             // mAccount and mContext in the runnerThread to create below |         // mAccount and mContext in the runnerThread to create below | ||||||
| 
 | 
 | ||||||
|         mListener = listener; |         mListener = listener; | ||||||
| 
 | 
 | ||||||
| @ -218,67 +234,67 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/** |     /** | ||||||
| 	 * Asynchronously executes the remote operation |      * Asynchronously executes the remote operation | ||||||
| 	 *  |      * | ||||||
| 	 * @param client			Client object to reach an ownCloud server |      * @param client          Client object to reach an ownCloud server | ||||||
|      *                          during the execution of the operation. |      *                        during the execution of the operation. | ||||||
| 	 * @param listener			Listener to be notified about the execution of the operation. |      * @param listener        Listener to be notified about the execution of the operation. | ||||||
| 	 * @param listenerHandler	Handler, if passed in, associated to the thread where the methods of |      * @param listenerHandler Handler, if passed in, associated to the thread where the methods of | ||||||
|      *                          the listener objects must be called. |      *                        the listener objects must be called. | ||||||
| 	 * @return					Thread were the remote operation is executed. |      * @return Thread were the remote operation is executed. | ||||||
| 	 */ |      */ | ||||||
| 	public Thread execute(OwnCloudClient client, |     public Thread execute(OwnCloudClient client, | ||||||
|                           OnRemoteOperationListener listener, Handler listenerHandler) { |                           OnRemoteOperationListener listener, Handler listenerHandler) { | ||||||
| 		if (client == null) { |         if (client == null) { | ||||||
| 			throw new IllegalArgumentException |             throw new IllegalArgumentException | ||||||
|                     ("Trying to execute a remote operation with a NULL OwnCloudClient"); |                     ("Trying to execute a remote operation with a NULL OwnCloudClient"); | ||||||
| 		} |         } | ||||||
| 		mClient = client; |         mClient = client; | ||||||
| 
 | 
 | ||||||
| 		if (listener == null) { |         if (listener == null) { | ||||||
| 			throw new IllegalArgumentException |             throw new IllegalArgumentException | ||||||
|                     ("Trying to execute a remote operation asynchronously " + |                     ("Trying to execute a remote operation asynchronously " + | ||||||
|                             "without a listener to notiy the result"); |                             "without a listener to notiy the result"); | ||||||
| 		} |         } | ||||||
| 		mListener = listener; |         mListener = listener; | ||||||
| 
 | 
 | ||||||
| 		if (listenerHandler != null) { |         if (listenerHandler != null) { | ||||||
|             mListenerHandler = listenerHandler; |             mListenerHandler = listenerHandler; | ||||||
| 		} |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		Thread runnerThread = new Thread(this); |         Thread runnerThread = new Thread(this); | ||||||
| 		runnerThread.start(); |         runnerThread.start(); | ||||||
| 		return runnerThread; |         return runnerThread; | ||||||
| 	} |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/** |     /** | ||||||
| 	 * Asynchronous execution of the operation  |      * Asynchronous execution of the operation | ||||||
| 	 * started by {@link RemoteOperation#execute(OwnCloudClient, |      * started by {@link RemoteOperation#execute(OwnCloudClient, | ||||||
|      *              OnRemoteOperationListener, Handler)}, |      * OnRemoteOperationListener, Handler)}, | ||||||
| 	 * and result posting. |      * and result posting. | ||||||
| 	 *  |      * | ||||||
| 	 * TODO refactor && clean the code; now it's a mess |      * TODO refactor && clean the code; now it's a mess | ||||||
| 	 */ |      */ | ||||||
|     @Override |     @Override | ||||||
|     public final void run() { |     public final void run() { | ||||||
|         RemoteOperationResult result = null; |         RemoteOperationResult result = null; | ||||||
|         boolean repeat = false; |         boolean repeat = false; | ||||||
|         do { |         do { | ||||||
|             try{ |             try { | ||||||
|                 if (mClient == null) { |                 if (mClient == null) { | ||||||
|                     if (mAccount != null && mContext != null) { |                     if (mAccount != null && mContext != null) { | ||||||
|                     	/** DEPRECATED BLOCK - will be removed at version 1.0 */ |                         /** DEPRECATED BLOCK - will be removed at version 1.0 */ | ||||||
|                         if (mCallerActivity != null) { |                         if (mCallerActivity != null) { | ||||||
|                             mClient = OwnCloudClientFactory.createOwnCloudClient( |                             mClient = OwnCloudClientFactory.createOwnCloudClient( | ||||||
|                             		mAccount, mContext, mCallerActivity); |                                     mAccount, mContext, mCallerActivity); | ||||||
|                         } else { |                         } else { | ||||||
|                         /** EOF DEPRECATED */ |                             /** EOF DEPRECATED */ | ||||||
|                         	OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); |                             OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||||
|                             mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). |                             mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). | ||||||
|                             		getClientFor(ocAccount, mContext); |                                     getClientFor(ocAccount, mContext); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                     } else { |                     } else { | ||||||
| @ -302,30 +318,69 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|                 result = run(mClient); |                 result = run(mClient); | ||||||
| 
 | 
 | ||||||
|             repeat = false; |             repeat = false; | ||||||
|         	/** DEPRECATED BLOCK - will be removed at version 1.0 ; don't trust in this code  | 
 | ||||||
|         	 * 						to trigger authentication update */ | 
 | ||||||
|             if (mCallerActivity != null && mAccount != null && mContext != null && |             AccountManager mAccountManager = AccountManager.get(mContext); | ||||||
|  | 
 | ||||||
|  |             String isOAuthStr = mAccountManager.getUserData(mAccount, | ||||||
|  |                     AccountUtils.Constants.KEY_SUPPORTS_OAUTH2); | ||||||
|  | 
 | ||||||
|  |             Boolean isOAuth = Boolean.valueOf(isOAuthStr); | ||||||
|  | 
 | ||||||
|  |             /** DEPRECATED BLOCK - will be removed at version 1.0 ; don't trust in this code | ||||||
|  |              * 						to trigger authentication update */ | ||||||
|  |             if (mAccount != null && mContext != null && | ||||||
|                     !result.isSuccess() && |                     !result.isSuccess() && | ||||||
|                     ResultCode.UNAUTHORIZED.equals(result.getCode()) |                     ResultCode.UNAUTHORIZED.equals(result.getCode()) | ||||||
|                 ) { |                     ) { | ||||||
|                 /// possible fail due to lack of authorization |                 /// possible fail due to lack of authorization | ||||||
|                 // in an operation performed in foreground |                 // in an operation performed in foreground | ||||||
|                 OwnCloudCredentials cred = mClient.getCredentials(); |                 OwnCloudCredentials cred = mClient.getCredentials(); | ||||||
|                 if (cred != null) { |                 if (cred != null) { | ||||||
|                     /// confirmed : unauthorized operation |                     /// confirmed : unauthorized operation | ||||||
|                     AccountManager am = AccountManager.get(mContext); | 
 | ||||||
|                     if (cred.authTokenExpires()) { |                     OwnCloudClient client; | ||||||
|                         am.invalidateAuthToken( |                     OwnCloudAccount ocAccount; | ||||||
|                                 mAccount.type,  | 
 | ||||||
|                                 cred.getAuthToken() |                     try { | ||||||
|                         ); |                         /// Step 1: Invalidate credentials of current account | ||||||
|                     } else { |                         ocAccount = new OwnCloudAccount(mAccount, mContext); | ||||||
|                         am.clearPassword(mAccount); |                         client = (OwnCloudClientManagerFactory.getDefaultSingleton(). | ||||||
|  |                                 removeClientFor(ocAccount)); | ||||||
|  |                         if (client != null) { | ||||||
|  |                             AccountManager am = AccountManager.get(mContext); | ||||||
|  |                             if (cred.authTokenExpires()) { | ||||||
|  |                                 am.invalidateAuthToken( // SAML & OAuth | ||||||
|  |                                         mAccount.type, | ||||||
|  |                                         cred.getAuthToken() | ||||||
|  |                                 ); | ||||||
|  |                             } else { //Basic | ||||||
|  |                                 am.clearPassword(mAccount); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         /// Step 2: Get new access token using refresh token | ||||||
|  |                         //  Params needed: clientId, clientSecret (switch credentials), grantype and | ||||||
|  |                         //  refresh token | ||||||
|  |                         String refreshToken = mAccountManager.getUserData(mAccount, | ||||||
|  |                                 AccountUtils.Constants.KEY_OAUTH2_REFRESH_TOKEN); | ||||||
|  | 
 | ||||||
|  | //                        mClient.executeMethod(postMethod); | ||||||
|  | 
 | ||||||
|  |                         /// Step 3: Save access token in account manager | ||||||
|  | 
 | ||||||
|  |                     } catch (AccountUtils.AccountNotFoundException e) { | ||||||
|  |                         e.printStackTrace(); | ||||||
|                     } |                     } | ||||||
|  | 
 | ||||||
|                     mClient = null; |                     mClient = null; | ||||||
|  | 
 | ||||||
|                     // when repeated, the creation of a new OwnCloudClient after erasing the saved |                     // when repeated, the creation of a new OwnCloudClient after erasing the saved | ||||||
|                     // credentials will trigger the login activity |                     // credentials will trigger the login activity | ||||||
|                     repeat = true; |                     if (isOAuth) { | ||||||
|  |                         repeat = true; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     result = null; |                     result = null; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -333,20 +388,19 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|         } while (repeat); |         } while (repeat); | ||||||
| 
 | 
 | ||||||
|         if (mAccount != null && mContext != null) { |         if (mAccount != null && mContext != null) { | ||||||
|         	// Save Client Cookies |             // Save Client Cookies | ||||||
|             AccountUtils.saveClient(mClient, mAccount, mContext); |             AccountUtils.saveClient(mClient, mAccount, mContext); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         final RemoteOperationResult resultToSend = result; |         final RemoteOperationResult resultToSend = result; | ||||||
|         if (mListenerHandler != null && mListener != null) { |         if (mListenerHandler != null && mListener != null) { | ||||||
|         	mListenerHandler.post(new Runnable() { |             mListenerHandler.post(new Runnable() { | ||||||
|                 @Override |                 @Override | ||||||
|                 public void run() { |                 public void run() { | ||||||
|                     mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend); |                     mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend); | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|         } |         } else if (mListener != null) { | ||||||
|         else if(mListener != null) { |  | ||||||
|             mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend); |             mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -355,10 +409,9 @@ public abstract class RemoteOperation implements Runnable { | |||||||
|     /** |     /** | ||||||
|      * Returns the current client instance to access the remote server. |      * Returns the current client instance to access the remote server. | ||||||
|      * |      * | ||||||
|      * @return      Current client instance to access the remote server. |      * @return Current client instance to access the remote server. | ||||||
|      */ |      */ | ||||||
|     public final OwnCloudClient getClient() { |     public final OwnCloudClient getClient() { | ||||||
|         return mClient; |         return mClient; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user