package com.owncloud.android.ui.activity; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.accounts.OperationCanceledException; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import com.owncloud.android.MainApp; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.status.OCCapability; import androidx.appcompat.app.AppCompatActivity; /** * Base activity with common behaviour for activities dealing with ownCloud {@link Account}s . */ public abstract class BaseActivity extends AppCompatActivity { private static final String TAG = BaseActivity.class.getSimpleName(); /** * ownCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */ private Account mCurrentAccount; /** * Capabilities of the server where {@link #mCurrentAccount} lives. */ private OCCapability mCapabilities; /** * Flag to signal when the value of mAccount was set. */ protected boolean mAccountWasSet; /** * Flag to signal when the value of mAccount was restored from a saved state. */ protected boolean mAccountWasRestored; /** * Access point to the cached database for the current ownCloud {@link Account}. */ private FileDataStorageManager mStorageManager; @Override protected void onNewIntent (Intent intent) { Log_OC.v(TAG, "onNewIntent() start"); Account current = AccountUtils.getCurrentOwnCloudAccount(this); if (current != null && mCurrentAccount != null && !mCurrentAccount.name.equals(current.name)) { mCurrentAccount = current; } Log_OC.v(TAG, "onNewIntent() stop"); } /** * Since ownCloud {@link Account}s can be managed from the system setting menu, the existence of the {@link * Account} associated to the instance must be checked every time it is restarted. */ @Override protected void onRestart() { Log_OC.v(TAG, "onRestart() start"); super.onRestart(); boolean validAccount = mCurrentAccount != null && AccountUtils.exists(mCurrentAccount, this); if (!validAccount) { swapToDefaultAccount(); } Log_OC.v(TAG, "onRestart() end"); } /** * Sets and validates the ownCloud {@link Account} associated to the Activity. * * If not valid, tries to swap it for other valid and existing ownCloud {@link Account}. * * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}. * * @param account New {@link Account} to set. * @param savedAccount When 'true', account was retrieved from a saved instance state. */ protected void setAccount(Account account, boolean savedAccount) { Account oldAccount = mCurrentAccount; boolean validAccount = account != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), account.name); if (validAccount) { mCurrentAccount = account; mAccountWasSet = true; mAccountWasRestored = savedAccount || mCurrentAccount.equals(oldAccount); } else { swapToDefaultAccount(); } } /** * Tries to swap the current ownCloud {@link Account} for other valid and existing. * * If no valid ownCloud {@link Account} exists, then the user is requested * to create a new ownCloud {@link Account}. * * POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}. */ protected void swapToDefaultAccount() { // default to the most recently used account Account newAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext()); if (newAccount == null) { /// no account available: force account creation createAccount(true); mAccountWasSet = false; mAccountWasRestored = false; } else { mAccountWasSet = true; mAccountWasRestored = newAccount.equals(mCurrentAccount); mCurrentAccount = newAccount; } } /** * Launches the account creation activity. * * @param mandatoryCreation When 'true', if an account is not created by the user, the app will be closed. * To use when no ownCloud account is available. */ protected void createAccount(boolean mandatoryCreation) { AccountManager am = AccountManager.get(getApplicationContext()); am.addAccount(MainApp.getAccountType(this), null, null, null, this, new AccountCreationCallback(mandatoryCreation), new Handler()); } /** * Called when the ownCloud {@link Account} associated to the Activity was just updated. * * Child classes must grant that state depending on the {@link Account} is updated. */ protected void onAccountSet(boolean stateWasRecovered) { if (getAccount() != null) { mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver()); mCapabilities = mStorageManager.getCapability(mCurrentAccount.name); } else { Log_OC.e(TAG, "onAccountChanged was called with NULL account associated!"); } } protected void setAccount(Account account) { mCurrentAccount = account; } /** * Getter for the capabilities of the server where the current OC account lives. * * @return Capabilities of the server where the current OC account lives. Null if the account is not * set yet. */ public OCCapability getCapabilities() { return mCapabilities; } /** * Getter for the ownCloud {@link Account} where the main {@link OCFile} handled by the activity * is located. * * @return OwnCloud {@link Account} where the main {@link OCFile} handled by the activity * is located. */ public Account getAccount() { return mCurrentAccount; } @Override protected void onStart() { super.onStart(); if (mAccountWasSet) { onAccountSet(mAccountWasRestored); } } public FileDataStorageManager getStorageManager() { return mStorageManager; } /** * Method that gets called when a new account has been successfully created. * * @param future */ protected void onAccountCreationSuccessful(AccountManagerFuture future) { // no special handling in base activity Log_OC.d(TAG,"onAccountCreationSuccessful"); } /** * Helper class handling a callback from the {@link AccountManager} after the creation of * a new ownCloud {@link Account} finished, successfully or not. */ public class AccountCreationCallback implements AccountManagerCallback { boolean mMandatoryCreation; /** * Constructor * * @param mandatoryCreation When 'true', if an account was not created, the app is closed. */ public AccountCreationCallback(boolean mandatoryCreation) { mMandatoryCreation = mandatoryCreation; } @Override public void run(AccountManagerFuture future) { boolean accountWasSet = false; if (future != null) { try { Bundle result; result = future.getResult(); String name = result.getString(AccountManager.KEY_ACCOUNT_NAME); String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE); if (AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), name)) { setAccount(new Account(name, type), false); accountWasSet = true; } onAccountCreationSuccessful(future); } catch (OperationCanceledException e) { Log_OC.d(TAG, "Account creation canceled"); } catch (Exception e) { Log_OC.e(TAG, "Account creation finished in exception: ", e); } } else { Log_OC.e(TAG, "Account creation callback with null bundle"); } if (mMandatoryCreation && !accountWasSet) { moveTaskToBack(true); } } } }