/* ownCloud Android client application
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2012-2014 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,
package com.owncloud.android.ui.activity;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.http.protocol.HTTP;
+import java.io.IOException;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
+import android.content.ServiceConnection;
import android.os.Bundle;
-import android.os.Parcelable;
-import android.webkit.MimeTypeMap;
+import android.os.Handler;
+import android.os.IBinder;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.widget.Toast;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
+import com.owncloud.android.authentication.AuthenticatorActivity;
+import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.FileOperationsHelper;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
+import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
+import com.owncloud.android.lib.common.operations.RemoteOperation;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.operations.CreateShareOperation;
+import com.owncloud.android.operations.UnshareLinkOperation;
-import com.owncloud.android.lib.accounts.OwnCloudAccount;
-import com.owncloud.android.lib.network.webdav.WebdavUtils;
-
+import com.owncloud.android.services.OperationsService;
+import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
+import com.owncloud.android.ui.dialog.LoadingDialog;
+import com.owncloud.android.utils.ErrorMessageAdapter;
import com.owncloud.android.utils.Log_OC;
*
* @author David A. Velasco
*/
-public abstract class FileActivity extends SherlockFragmentActivity {
+public class FileActivity extends SherlockFragmentActivity
+implements OnRemoteOperationListener, ComponentsGetter {
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 EXTRA_FROM_NOTIFICATION= "com.owncloud.android.ui.activity.FROM_NOTIFICATION";
- public static final String TAG = FileActivity.class.getSimpleName();
+ public static final String TAG = FileActivity.class.getSimpleName();
+
+ private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
+ private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";;
/** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located. */
/** Flag to signal if the activity is launched by a notification */
private boolean mFromNotification;
-
+ /** Messages handler associated to the main thread and the life cycle of the activity */
+ private Handler mHandler;
+
+ /** Access point to the cached database for the current ownCloud {@link Account} */
+ private FileDataStorageManager mStorageManager = null;
+
+ private FileOperationsHelper mFileOperationsHelper;
+
+ private ServiceConnection mOperationsServiceConnection = null;
+
+ private OperationsServiceBinder mOperationsServiceBinder = null;
+
+ protected FileDownloaderBinder mDownloaderBinder = null;
+ protected FileUploaderBinder mUploaderBinder = null;
+ private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
+
/**
* Loads the ownCloud {@link Account} and main {@link OCFile} to be handled by the instance of
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mHandler = new Handler();
+ mFileOperationsHelper = new FileOperationsHelper(this);
Account account;
if(savedInstanceState != null) {
account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT);
mFile = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE);
mFromNotification = savedInstanceState.getBoolean(FileActivity.EXTRA_FROM_NOTIFICATION);
+ mFileOperationsHelper.setOpIdWaitingFor(
+ savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
+ );
} else {
account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
}
setAccount(account, savedInstanceState != null);
-
+
+ mOperationsServiceConnection = new OperationsServiceConnection();
+ bindService(new Intent(this, OperationsService.class), mOperationsServiceConnection, Context.BIND_AUTO_CREATE);
+
+ mDownloadServiceConnection = newTransferenceServiceConnection();
+ if (mDownloadServiceConnection != null) {
+ bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+ mUploadServiceConnection = newTransferenceServiceConnection();
+ if (mUploadServiceConnection != null) {
+ bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+
}
if (!validAccount) {
swapToDefaultAccount();
}
-
}
@Override
protected void onStart() {
super.onStart();
+
if (mAccountWasSet) {
onAccountSet(mAccountWasRestored);
}
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (mOperationsServiceBinder != null) {
+ doOnResumeAndBound();
+ }
+
+ }
+
+ @Override
+ protected void onPause() {
+ // Save cookies here
+ Log_OC.wtf(TAG, "Saving Cookies" );
+ if (mAccount != null) {
+ try {
+ ((MainApp)getApplicationContext()).getOwnCloudClientManager().
+ saveClient(mAccount, this);
+
+ // TODO get rid of the exceptions
+ } catch (AccountNotFoundException e) {
+ e.printStackTrace();
+ } catch (AuthenticatorException e) {
+ e.printStackTrace();
+ } catch (OperationCanceledException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (mOperationsServiceBinder != null) {
+ mOperationsServiceBinder.removeOperationListener(this);
+ }
+
+ super.onPause();
+ }
+
+
+ @Override
+ protected void onDestroy() {
+ if (mOperationsServiceConnection != null) {
+ unbindService(mOperationsServiceConnection);
+ mOperationsServiceBinder = null;
+ }
+ if (mDownloadServiceConnection != null) {
+ unbindService(mDownloadServiceConnection);
+ mDownloadServiceConnection = null;
+ }
+ if (mUploadServiceConnection != null) {
+ unbindService(mUploadServiceConnection);
+ mUploadServiceConnection = null;
+ }
+ super.onDestroy();
+ }
+
/**
* Sets and validates the ownCloud {@link Account} associated to the Activity.
outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
+ outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
}
}
- /**
- * @return 'True' if the server supports the Share API
- */
- public boolean isSharedSupported() {
- if (getAccount() != null) {
- AccountManager accountManager = AccountManager.get(this);
- return Boolean.parseBoolean(accountManager.getUserData(getAccount(), OwnCloudAccount.Constants.KEY_SUPPORTS_SHARE_API));
- }
- return false;
+ public OperationsServiceBinder getOperationsServiceBinder() {
+ return mOperationsServiceBinder;
}
+
+ protected ServiceConnection newTransferenceServiceConnection() {
+ return null;
+ }
+
/**
* Helper class handling a callback from the {@link AccountManager} after the creation of
*
* Child classes must grant that state depending on the {@link Account} is updated.
*/
- protected abstract void onAccountSet(boolean stateWasRecovered);
+ protected void onAccountSet(boolean stateWasRecovered) {
+ if (getAccount() != null) {
+ mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
+
+ } else {
+ Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
+ }
+ }
+
+
+ public FileDataStorageManager getStorageManager() {
+ return mStorageManager;
+ }
+
+
+ public OnRemoteOperationListener getRemoteOperationListener() {
+ return this;
+ }
+
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+ public FileOperationsHelper getFileOperationsHelper() {
+ return mFileOperationsHelper;
+ }
-
- public void openFile(OCFile file) {
- if (file != null) {
- String storagePath = file.getStoragePath();
- String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+ /**
+ *
+ * @param operation Removal operation performed.
+ * @param result Result of the removal.
+ */
+ @Override
+ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+ Log_OC.d(TAG, "Received result of operation in FileActivity - common behaviour for all the FileActivities ");
+
+ mFileOperationsHelper.setOpIdWaitingFor(Long.MAX_VALUE);
+
+ if (!result.isSuccess() && (
+ result.getCode() == ResultCode.UNAUTHORIZED ||
+ result.isIdPRedirection() ||
+ (result.isException() && result.getException() instanceof AuthenticatorException)
+ )) {
- 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);
+ requestCredentialsUpdate();
- 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);
- }
+ if (result.getCode() == ResultCode.UNAUTHORIZED) {
+ dismissLoadingDialog();
+ Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast.LENGTH_LONG);
+ t.show();
}
+
+ } else if (operation instanceof CreateShareOperation) {
+ onCreateShareOperationFinish((CreateShareOperation) operation, result);
- 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");
- }
+ } else if (operation instanceof UnshareLinkOperation) {
+ onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result);
+
+ }
}
- /*
- public void shareFileWithLink(OCFile file) {
- if (file != null) {
+ protected void requestCredentialsUpdate() {
+ Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+ updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
+ updateAccountCredentials.putExtra(
+ AuthenticatorActivity.EXTRA_ACTION,
+ AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
+ updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ startActivity(updateAccountCredentials);
+ }
+
+
+ private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+ dismissLoadingDialog();
+ if (result.isSuccess()) {
+ updateFileFromDB();
- Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
- intentToShareLink.putExtra(Intent.EXTRA_TEXT, "https://fake.url.lolo");
- intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE);
+ Intent sendIntent = operation.getSendIntent();
+ startActivity(sendIntent);
- Intent chooserIntent = Intent.createChooser(intentToShareLink, getString(R.string.action_share_file));
- startActivity(chooserIntent);
+ } else {
+ Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast.LENGTH_LONG);
+ t.show();
+ }
+ }
+
+
+ private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) {
+ dismissLoadingDialog();
+
+ if (result.isSuccess()){
+ updateFileFromDB();
} else {
- Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
+ Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+ Toast.LENGTH_LONG);
+ t.show();
+ }
+ }
+
+
+ private void updateFileFromDB(){
+ OCFile file = getStorageManager().getFileByPath(getFile().getRemotePath());
+ if (file != null) {
+ setFile(file);
+ }
+ }
+
+ /**
+ * Show loading dialog
+ */
+ public void showLoadingDialog() {
+ // Construct dialog
+ LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
+ FragmentManager fm = getSupportFragmentManager();
+ FragmentTransaction ft = fm.beginTransaction();
+ loading.show(ft, DIALOG_WAIT_TAG);
+
+ }
+
+
+ /**
+ * Dismiss loading dialog
+ */
+ public void dismissLoadingDialog(){
+ Fragment frag = getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
+ if (frag != null) {
+ LoadingDialog loading = (LoadingDialog) frag;
+ loading.dismiss();
}
}
- */
+
- public void shareFileWithLink(OCFile file) {
- if (file != null) {
-
- //CreateShareOperation createShare = new CreateShareOperation(file.getRemotePath(), ShareType.PUBLIC_LINK, "", false, "", 1);
- //createShare.execute(getAccount(), this, this, mHandler, this);
-
- String link = "https://fake.url.lolo";
- Intent chooserIntent = null;
- List<Intent> targetedShareIntents = new ArrayList<Intent>();
- List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(createShareWithLinkIntent(link), PackageManager.MATCH_DEFAULT_ONLY);
- String myPackageName = getPackageName();
- if (!resInfo.isEmpty()) {
- for (ResolveInfo info : resInfo) {
- if (!info.activityInfo.packageName.equalsIgnoreCase(myPackageName)) {
- Intent targetedShare = createTargetedShare(link, info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
- targetedShareIntents.add(targetedShare);
- }
- }
+ private void doOnResumeAndBound() {
+ mOperationsServiceBinder.addOperationListener(FileActivity.this, mHandler);
+ long waitingForOpId = mFileOperationsHelper.getOpIdWaitingFor();
+ if (waitingForOpId <= Integer.MAX_VALUE) {
+ boolean wait = mOperationsServiceBinder.dispatchResultIfFinished((int)waitingForOpId, this);
+ if (!wait ) {
+ dismissLoadingDialog();
}
- if (targetedShareIntents.size() > 0) {
- Intent firstTargeted = targetedShareIntents.remove(0);
- chooserIntent = Intent.createChooser(firstTargeted, getString(R.string.action_share_file));
- chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[] {}));
+ }
+ }
+
+
+ /**
+ * Implements callback methods for service binding. Passed as a parameter to {
+ */
+ private class OperationsServiceConnection implements ServiceConnection {
+
+ @Override
+ public void onServiceConnected(ComponentName component, IBinder service) {
+ if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
+ Log_OC.d(TAG, "Operations service connected");
+ mOperationsServiceBinder = (OperationsServiceBinder) service;
+ /*if (!mOperationsServiceBinder.isPerformingBlockingOperation()) {
+ dismissLoadingDialog();
+ }*/
+ doOnResumeAndBound();
+
} else {
- // to show standard message
- chooserIntent = Intent.createChooser(null, getString(R.string.action_share_file));
+ return;
}
- startActivity(chooserIntent);
-
- } else {
- Log_OC.wtf(TAG, "Trying to open a NULL OCFile");
}
- }
-
- private Intent createTargetedShare(String link, String packageName, String className) {
- //Intent targetedShare = createShareWithLinkIntent(link);
- Intent targetedShare=new Intent(Intent.ACTION_MAIN);
+
- targetedShare.addCategory(Intent.CATEGORY_LAUNCHER);
- targetedShare.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- Log_OC.e("LOLO", "className: " + className + "\npackageName: " + packageName + "\n");
- targetedShare.setClassName(packageName, className);
- return targetedShare;
+ @Override
+ public void onServiceDisconnected(ComponentName component) {
+ if (component.equals(new ComponentName(FileActivity.this, OperationsService.class))) {
+ Log_OC.d(TAG, "Operations service disconnected");
+ mOperationsServiceBinder = null;
+ // TODO whatever could be waiting for the service is unbound
+ }
+ }
}
- private Intent createShareWithLinkIntent(String link) {
- Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
- intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
- intentToShareLink.setType(HTTP.PLAIN_TEXT_TYPE);
- return intentToShareLink;
+ @Override
+ public FileDownloaderBinder getFileDownloaderBinder() {
+ return mDownloaderBinder;
}
+
+
+ @Override
+ public FileUploaderBinder getFileUploaderBinder() {
+ return mUploaderBinder;
+ };
}