/* ownCloud Android client application
* Copyright (C) 2011 Bartek Przybylski
* 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 .
*
*/
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.net.Uri;
import android.os.Bundle;
import android.webkit.MimeTypeMap;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountAuthenticator;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.OCFile;
import eu.alefzero.webdav.WebdavUtils;
/**
* Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
*
* @author David A. Velasco
*/
public abstract class FileActivity extends SherlockFragmentActivity {
public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
public static final String EXTRA_WAITING_TO_PREVIEW = "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW";
public static final String TAG = FileActivity.class.getSimpleName();
/** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
private Account mAccount;
/** Main {@link OCFile} handled by the activity.*/
private OCFile mFile;
/** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud {@link Account} */
private boolean mRedirectingToSetupAccount = false;
/**
* Loads the cownCloud {@link Account} and main {@link OCFile} to be handled by the instance of
* the {@link FileActivity}.
*
* Grants that a valid ownCloud {@link Account} is associated to the instance, or that the user
* is requested to create a new one.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
mAccount = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
} else {
mAccount = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
}
grantValidAccount();
if (mAccount != null) {
onAccountSet(savedInstanceState != null);
}
}
/**
* 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() {
super.onRestart();
Account oldAccount = mAccount;
grantValidAccount();
if (mAccount != null && !mAccount.equals(oldAccount)) {
onAccountSet(false);
}
}
/**
* Validates the ownCloud {@link Account} associated to the Activity any time it is restarted.
*
* If not valid, tries to swap it for other valid and existing ownCloud {@link Account}.
*
* If no valid ownCloud {@link Account} exists, mAccount is set to NULL and the user is requested
* to create a new ownCloud {@link Account}.
*/
private void grantValidAccount() {
boolean validAccount = (mAccount != null && AccountUtils.setCurrentOwnCloudAccount(getApplicationContext(), mAccount.name));
if (!validAccount) {
// get most recently used account as default account
mAccount = AccountUtils.getCurrentOwnCloudAccount(getApplicationContext());
if (mAccount == null) {
/// no account available: force account creation
createFirstAccount();
mRedirectingToSetupAccount = true;
}
}
}
/**
* Launches the account creation activity. To use when no ownCloud account is available
*/
private void createFirstAccount() {
AccountManager am = AccountManager.get(getApplicationContext());
am.addAccount(AccountAuthenticator.ACCOUNT_TYPE,
AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD,
null,
null,
this,
new AccountCreationCallback(),
null);
}
/**
* {@inheritDoc}
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
}
/**
* Getter for the main {@link OCFile} handled by the activity.
*
* @return Main {@link OCFile} handled by the activity.
*/
public OCFile getFile() {
return mFile;
}
/**
* Setter for the main {@link OCFile} handled by the activity.
*
* @param file Main {@link OCFile} to be handled by the activity.
*/
public void setFile(OCFile file) {
mFile = file;
}
/**
* 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 mAccount;
}
/**
* @return 'True' when the Activity is finishing to enforce the setup of a new account.
*/
protected boolean isRedirectingToSetupAccount() {
return mRedirectingToSetupAccount;
}
/**
* Helper class handling a callback from the {@link AccountManager} after the creation of
* a new ownCloud {@link Account} finished, successfully or not.
*
* At this moment, only called after the creation of the first account.
*
* @author David A. Velasco
*/
public class AccountCreationCallback implements AccountManagerCallback {
@Override
public void run(AccountManagerFuture future) {
FileActivity.this.mRedirectingToSetupAccount = 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)) {
FileActivity.this.mAccount = new Account(name, type);
FileActivity.this.onAccountSet(false);
}
} catch (OperationCanceledException e) {
Log_OC.e(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 (mAccount == null) {
finish();
}
}
}
/**
* 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 abstract void onAccountSet(boolean stateWasRecovered);
public void openFile(OCFile file) {
if (file != null) {
String storagePath = file.getStoragePath();
String encodedStoragePath = WebdavUtils.encodePath(storagePath);
Intent intentForSavedMimeType = new Intent(Intent.ACTION_VIEW);
intentForSavedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), file.getMimetype());
intentForSavedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Intent intentForGuessedMimeType = null;
if (storagePath.lastIndexOf('.') >= 0) {
String guessedMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
if (guessedMimeType != null && !guessedMimeType.equals(file.getMimetype())) {
intentForGuessedMimeType = new Intent(Intent.ACTION_VIEW);
intentForGuessedMimeType.setDataAndType(Uri.parse("file://"+ encodedStoragePath), guessedMimeType);
intentForGuessedMimeType.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
}
Intent chooserIntent = null;
if (intentForGuessedMimeType != null) {
chooserIntent = Intent.createChooser(intentForGuessedMimeType, getString(R.string.actionbar_open_with));
} else {
chooserIntent = Intent.createChooser(intentForSavedMimeType, getString(R.string.actionbar_open_with));
}
startActivity(chooserIntent);
} else {
Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
}
}
}