1 /* ownCloud Android client application 
   2  *   Copyright (C) 2011  Bartek Przybylski 
   3  *   Copyright (C) 2012-2013 ownCloud Inc. 
   5  *   This program is free software: you can redistribute it and/or modify 
   6  *   it under the terms of the GNU General Public License version 2, 
   7  *   as published by the Free Software Foundation. 
   9  *   This program is distributed in the hope that it will be useful, 
  10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of 
  11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  12  *   GNU General Public License for more details. 
  14  *   You should have received a copy of the GNU General Public License 
  15  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  19 package com
.owncloud
.android
.ui
.activity
; 
  21 import android
.accounts
.Account
; 
  22 import android
.accounts
.AccountManager
; 
  23 import android
.accounts
.AccountManagerCallback
; 
  24 import android
.accounts
.AccountManagerFuture
; 
  25 import android
.accounts
.OperationCanceledException
; 
  26 import android
.os
.Bundle
; 
  27 import android
.os
.Handler
; 
  29 import com
.actionbarsherlock
.app
.SherlockFragmentActivity
; 
  30 import com
.owncloud
.android
.MainApp
; 
  31 import com
.owncloud
.android
.authentication
.AccountUtils
; 
  32 import com
.owncloud
.android
.datamodel
.FileDataStorageManager
; 
  33 import com
.owncloud
.android
.datamodel
.OCFile
; 
  34 import com
.owncloud
.android
.files
.FileOperationsHelper
; 
  35 import com
.owncloud
.android
.lib
.operations
.common
.OnRemoteOperationListener
; 
  36 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperation
; 
  37 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperationResult
; 
  39 import com
.owncloud
.android
.utils
.Log_OC
; 
  43  * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s . 
  45  * @author David A. Velasco 
  47 public class FileActivity 
extends SherlockFragmentActivity 
implements OnRemoteOperationListener 
{ 
  49     public static final String EXTRA_FILE 
= "com.owncloud.android.ui.activity.FILE"; 
  50     public static final String EXTRA_ACCOUNT 
= "com.owncloud.android.ui.activity.ACCOUNT"; 
  51     public static final String EXTRA_WAITING_TO_PREVIEW 
= "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW"; 
  52     public static final String EXTRA_FROM_NOTIFICATION
= "com.owncloud.android.ui.activity.FROM_NOTIFICATION"; 
  54     public static final String TAG 
= FileActivity
.class.getSimpleName(); 
  57     /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */ 
  58     private Account mAccount
; 
  60     /** Main {@link OCFile} handled by the activity.*/ 
  63     /** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud {@link Account} */ 
  64     private boolean mRedirectingToSetupAccount 
= false
; 
  66     /** Flag to signal when the value of mAccount was set */  
  67     private boolean mAccountWasSet
; 
  69     /** Flag to signal when the value of mAccount was restored from a saved state */  
  70     private boolean mAccountWasRestored
; 
  72     /** Flag to signal if the activity is launched by a notification */ 
  73     private boolean mFromNotification
; 
  75     /** Messages handler associated to the main thread and the life cycle of the activity */ 
  76     private Handler mHandler
; 
  78     /** Access point to the cached database for the current ownCloud {@link Account} */ 
  79     private FileDataStorageManager mStorageManager 
= null
; 
  81     private FileOperationsHelper mFileOperationsHelper
; 
  85      * Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of  
  86      * the {@link FileActivity}. 
  88      * Grants that a valid ownCloud {@link Account} is associated to the instance, or that the user  
  89      * is requested to create a new one. 
  92     protected void onCreate(Bundle savedInstanceState
) { 
  93         super.onCreate(savedInstanceState
); 
  94         mHandler 
= new Handler(); 
  95         mFileOperationsHelper 
= new FileOperationsHelper(); 
  97         if(savedInstanceState 
!= null
) { 
  98             account 
= savedInstanceState
.getParcelable(FileActivity
.EXTRA_ACCOUNT
); 
  99             mFile 
= savedInstanceState
.getParcelable(FileActivity
.EXTRA_FILE
); 
 100             mFromNotification 
= savedInstanceState
.getBoolean(FileActivity
.EXTRA_FROM_NOTIFICATION
); 
 102             account 
= getIntent().getParcelableExtra(FileActivity
.EXTRA_ACCOUNT
); 
 103             mFile 
= getIntent().getParcelableExtra(FileActivity
.EXTRA_FILE
); 
 104             mFromNotification 
= getIntent().getBooleanExtra(FileActivity
.EXTRA_FROM_NOTIFICATION
, false
); 
 107         setAccount(account
, savedInstanceState 
!= null
); 
 113      *  Since ownCloud {@link Account}s can be managed from the system setting menu,  
 114      *  the existence of the {@link Account} associated to the instance must be checked  
 115      *  every time it is restarted. 
 118     protected void onRestart() { 
 120         boolean validAccount 
= (mAccount 
!= null 
&& AccountUtils
.setCurrentOwnCloudAccount(getApplicationContext(), mAccount
.name
)); 
 122             swapToDefaultAccount(); 
 129     protected void onStart() { 
 131         if (mAccountWasSet
) { 
 132             onAccountSet(mAccountWasRestored
); 
 138      *  Sets and validates the ownCloud {@link Account} associated to the Activity.  
 140      *  If not valid, tries to swap it for other valid and existing ownCloud {@link Account}. 
 142      *  POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.  
 144      *  @param account          New {@link Account} to set. 
 145      *  @param savedAccount     When 'true', account was retrieved from a saved instance state. 
 147     private void setAccount(Account account
, boolean savedAccount
) { 
 148         Account oldAccount 
= mAccount
; 
 149         boolean validAccount 
= (account 
!= null 
&& AccountUtils
.setCurrentOwnCloudAccount(getApplicationContext(), account
.name
)); 
 152             mAccountWasSet 
= true
; 
 153             mAccountWasRestored 
= (savedAccount 
|| mAccount
.equals(oldAccount
)); 
 156             swapToDefaultAccount(); 
 162      *  Tries to swap the current ownCloud {@link Account} for other valid and existing.  
 164      *  If no valid ownCloud {@link Account} exists, the the user is requested  
 165      *  to create a new ownCloud {@link Account}. 
 167      *  POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}. 
 169      *  @return     'True' if the checked {@link Account} was valid. 
 171     private void swapToDefaultAccount() { 
 172         // default to the most recently used account 
 173         Account newAccount  
= AccountUtils
.getCurrentOwnCloudAccount(getApplicationContext()); 
 174         if (newAccount 
== null
) { 
 175             /// no account available: force account creation 
 176             createFirstAccount(); 
 177             mRedirectingToSetupAccount 
= true
; 
 178             mAccountWasSet 
= false
; 
 179             mAccountWasRestored 
= false
; 
 182             mAccountWasSet 
= true
; 
 183             mAccountWasRestored 
= (newAccount
.equals(mAccount
)); 
 184             mAccount 
= newAccount
; 
 190      * Launches the account creation activity. To use when no ownCloud account is available 
 192     private void createFirstAccount() { 
 193         AccountManager am 
= AccountManager
.get(getApplicationContext()); 
 194         am
.addAccount(MainApp
.getAccountType(),  
 199                         new AccountCreationCallback(),                         
 208     protected void onSaveInstanceState(Bundle outState
) { 
 209         super.onSaveInstanceState(outState
); 
 210         outState
.putParcelable(FileActivity
.EXTRA_FILE
, mFile
); 
 211         outState
.putParcelable(FileActivity
.EXTRA_ACCOUNT
, mAccount
); 
 212         outState
.putBoolean(FileActivity
.EXTRA_FROM_NOTIFICATION
, mFromNotification
); 
 217      * Getter for the main {@link OCFile} handled by the activity. 
 219      * @return  Main {@link OCFile} handled by the activity. 
 221     public OCFile 
getFile() { 
 227      * Setter for the main {@link OCFile} handled by the activity. 
 229      * @param file  Main {@link OCFile} to be handled by the activity. 
 231     public void setFile(OCFile file
) { 
 237      * Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity is located. 
 239      * @return  OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. 
 241     public Account 
getAccount() { 
 246      * @return Value of mFromNotification: True if the Activity is launched by a notification 
 248     public boolean fromNotification() { 
 249         return mFromNotification
; 
 253      * @return  'True' when the Activity is finishing to enforce the setup of a new account. 
 255     protected boolean isRedirectingToSetupAccount() { 
 256         return mRedirectingToSetupAccount
; 
 261      * Helper class handling a callback from the {@link AccountManager} after the creation of 
 262      * a new ownCloud {@link Account} finished, successfully or not. 
 264      * At this moment, only called after the creation of the first account. 
 266      * @author David A. Velasco 
 268     public class AccountCreationCallback 
implements AccountManagerCallback
<Bundle
> { 
 271         public void run(AccountManagerFuture
<Bundle
> future
) { 
 272             FileActivity
.this.mRedirectingToSetupAccount 
= false
; 
 273             boolean accountWasSet 
= false
; 
 274             if (future 
!= null
) { 
 277                     result 
= future
.getResult(); 
 278                     String name 
= result
.getString(AccountManager
.KEY_ACCOUNT_NAME
); 
 279                     String type 
= result
.getString(AccountManager
.KEY_ACCOUNT_TYPE
); 
 280                     if (AccountUtils
.setCurrentOwnCloudAccount(getApplicationContext(), name
)) { 
 281                         setAccount(new Account(name
, type
), false
); 
 282                         accountWasSet 
= true
; 
 284                 } catch (OperationCanceledException e
) { 
 285                     Log_OC
.d(TAG
, "Account creation canceled"); 
 287                 } catch (Exception e
) { 
 288                     Log_OC
.e(TAG
, "Account creation finished in exception: ", e
); 
 292                 Log_OC
.e(TAG
, "Account creation callback with null bundle"); 
 294             if (!accountWasSet
) { 
 295                 moveTaskToBack(true
); 
 303      *  Called when the ownCloud {@link Account} associated to the Activity was just updated. 
 305      *  Child classes must grant that state depending on the {@link Account} is updated. 
 307     protected void onAccountSet(boolean stateWasRecovered
) { 
 308         if (getAccount() != null
) { 
 309             mStorageManager 
= new FileDataStorageManager(getAccount(), getContentResolver()); 
 312             Log_OC
.wtf(TAG
, "onAccountChanged was called with NULL account associated!"); 
 317     public FileDataStorageManager 
getStorageManager() { 
 318         return mStorageManager
; 
 322     public OnRemoteOperationListener 
getRemoteOperationListener() { 
 327     public Handler 
getHandler() { 
 331     public FileOperationsHelper 
getFileOperationsHelper() { 
 332         return mFileOperationsHelper
; 
 337      * @param operation     Removal operation performed. 
 338      * @param result        Result of the removal. 
 341     public void onRemoteOperationFinish(RemoteOperation operation
, RemoteOperationResult result
) { 
 342         // does nothing ; to override in child classes  
 343         Log_OC
.d(TAG
, "Received result of operation in FileActivity");