From: David A. Velasco Date: Thu, 4 Apr 2013 14:44:30 +0000 (+0200) Subject: Merge branch 'develop' into feature_previews X-Git-Tag: oc-android-1.4.3~39^2~6 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/77ddd1ccb62e8b70580b8f410dda703a269f224f?hp=--cc Merge branch 'develop' into feature_previews Conflicts: AndroidManifest.xml res/menu/file_context_menu.xml res/menu/menu.xml res/values-de-rDE/strings.xml res/values/strings.xml src/com/owncloud/android/files/services/FileUploader.java src/com/owncloud/android/operations/UploadFileOperation.java src/com/owncloud/android/ui/activity/FileDisplayActivity.java --- 77ddd1ccb62e8b70580b8f410dda703a269f224f diff --cc AndroidManifest.xml index 279beba2,32c4655a..42c51748 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@@ -135,20 -132,21 +140,20 @@@ - - + + + - + - + - + - - - - + + diff --cc res/menu/file_actions_menu.xml index 8a06e7ea,00000000..bce33ebc mode 100644,000000..100644 --- a/res/menu/file_actions_menu.xml +++ b/res/menu/file_actions_menu.xml @@@ -1,12 -1,0 +1,31 @@@ + ++ + + + + + + + + + + + diff --cc res/menu/main_menu.xml index 2aff9e36,00000000..a3b8d5e0 mode 100644,000000..100644 --- a/res/menu/main_menu.xml +++ b/res/menu/main_menu.xml @@@ -1,11 -1,0 +1,30 @@@ + ++ + + + + + + + + + diff --cc res/values-de-rDE/strings.xml index 79014c51,0646f111..9f20caeb --- a/res/values-de-rDE/strings.xml +++ b/res/values-de-rDE/strings.xml @@@ -239,7 -216,14 +239,17 @@@ Beide behalten Überschreiben Nicht hochladen + Bildvorschau + Das Bild kann nicht angezeigt werden + "Nicht genug Speicherplatz um das Bild anzuzeigen + + Fehlgeschlagene Sofortuploads + Fehlgeschlagene Sofortuploads + Auflistung aller fehlgeschlagenen Softuploads + Alle auswählen + Ausgewählte wiederholen + Ausgewählte löschen + Versuche ausgewählte erneut hochzuladen + Load more Picrures + do nothing you are not online for instant upload diff --cc res/values/strings.xml index 45b9222e,644e618b..9abfa798 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@@ -88,18 -84,14 +86,16 @@@ Save & Exit Leave %1$s Error + Loading … + Unknown error About - Delete account Create account - Upload from … Directory name - Uploading … - %1$d%% Uploading %2$s - Upload succeeded + Uploading … + %1$d%% Uploading %2$s + Upload succeeded %1$s was successfully uploaded %1$d files were successfully uploaded Upload failed @@@ -111,19 -103,17 +107,18 @@@ %1$s was successfully downloaded Download failed Download of %1$s could not be completed + Not downloaded yet Choose account Contacts - Synchronization failed + Synchronization failed Synchronization of %1$s could not be completed - Conflicts found - %1$d kept-in-sync files could not be sync\'ed + Conflicts found + %1$d kept-in-sync files could not be sync\'ed Kept-in-sync files failed - Contents of %1$d files could not be sync\'ed (%2$d conflicts) - Some local files were forgotten - %1$d files out of the %2$s directory could not be copied into - "As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to. - + Contents of %1$d files could not be sync\'ed (%2$d conflicts) + Some local files were forgotten + %1$d files out of the %2$s directory could not be copied into + "As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to. "Move all" "All files were moved" "Some files could not be moved" @@@ -145,39 -132,18 +137,39 @@@ Incorrect App PIN App PIN removed App PIN stored - + + "%1$s music player" + "%1$s (playing)" + "%1$s (loading)" + "%1$s playback finished" + No media file found + No account provided + File not in a valid account + Unsupported media codec + Media file could not be read + Media file not correctly encoded + Too much time trying to play + Media file cannot be streamed + Media file cannot be played with the stock media player + Security error trying to play %1$s + Input error trying to play %1$s + Unexpected error trying to play %1$s + Previous track button + Rewind button + Play or pause button + Fast forward button + Next track button - 15 Minutes - 30 Minutes - 60 Minutes - - + 15 Minutes + 30 Minutes + 60 Minutes + - 15 - 30 - 60 - + 15 + 30 + 60 + + Trying to login… No network connection No network connection has been detected, check your Internet connection and try again. @@@ -256,37 -212,35 +238,46 @@@ Issued by: Common name: Organization: - Organizational unit: - Country: - State: - Location: + Organizational unit: + Country: + State: + Location: Validity: From: - To: - Signature: - Algorithm: - This is a placeholder + To: + Signature: + Algorithm: + + This is a placeholder + placeholder.txt + PNG Image + 389 KB + 2012/05/18 12:23 PM + 12:23:45 + Upload pictures via WiFi only - /InstantUpload - + /InstantUpload Update conflict Remote file %s is not synchronized with local file. Continuing will replace content of file on server. Keep both Overwrite Don\'t upload - + + Image preview + This image can not be shown + "Not enough memory to show this image + %1$s could not be copied to %2$s local directory - + Failed InstantUpload" + Failed instant uploads + Summary of all failed instant uploads + select all + retry all selected + delete all selected from uploadqueue + retry to upload the image: + Load more Picrures + do nothing you are not online for instant upload + Failure Message: + Please check your server configuration,maybe your quota is exceeded. - + diff --cc src/com/owncloud/android/files/services/FileUploader.java index e16d75ce,3de51b6e..330b793c --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@@ -68,9 -47,28 +49,30 @@@ import android.os.Process import android.util.Log; import android.webkit.MimeTypeMap; import android.widget.RemoteViews; + import android.widget.Toast; import com.owncloud.android.R; + import com.owncloud.android.authenticator.AccountAuthenticator; + import com.owncloud.android.datamodel.FileDataStorageManager; + import com.owncloud.android.datamodel.OCFile; + import com.owncloud.android.db.DbHandler; + import com.owncloud.android.network.OwnCloudClientUtils; + import com.owncloud.android.operations.ChunkedUploadFileOperation; + import com.owncloud.android.operations.RemoteOperationResult; + import com.owncloud.android.operations.RemoteOperationResult.ResultCode; + import com.owncloud.android.operations.UploadFileOperation; + import com.owncloud.android.ui.activity.FailedUploadActivity; + import com.owncloud.android.ui.activity.FileDetailActivity; + import com.owncloud.android.ui.activity.InstantUploadActivity; + import com.owncloud.android.ui.fragment.FileDetailFragment; ++import com.owncloud.android.ui.preview.PreviewImageActivity; ++import com.owncloud.android.ui.preview.PreviewImageFragment; + import com.owncloud.android.utils.OwnCloudVersion; + + import eu.alefzero.webdav.OnDatatransferProgressListener; import eu.alefzero.webdav.WebdavClient; + import eu.alefzero.webdav.WebdavEntry; + import eu.alefzero.webdav.WebdavUtils; public class FileUploader extends Service implements OnDatatransferProgressListener { @@@ -257,10 -271,9 +275,10 @@@ } mPendingUploads.putIfAbsent(uploadKey, newUpload); newUpload.addDatatransferProgressListener(this); + newUpload.addDatatransferProgressListener((FileUploaderBinder)mBinder); requestedUploads.add(uploadKey); } - + } catch (IllegalArgumentException e) { Log.e(TAG, "Not enough information provided in intent: " + e.getMessage()); return START_NOT_STICKY; @@@ -295,29 -309,15 +314,30 @@@ public IBinder onBind(Intent arg0) { return mBinder; } + + /** + * Called when ALL the bound clients were onbound. + */ + @Override + public boolean onUnbind(Intent intent) { + ((FileUploaderBinder)mBinder).clearListeners(); + return false; // not accepting rebinding (default behaviour) + } + /** - * Binder to let client components to perform operations on the queue of uploads. + * Binder to let client components to perform operations on the queue of + * uploads. * - * It provides by itself the available operations. + * It provides by itself the available operations. */ - public class FileUploaderBinder extends Binder { - + public class FileUploaderBinder extends Binder implements OnDatatransferProgressListener { + + /** + * Map of listeners that will be reported about progress of uploads from a {@link FileUploaderBinder} instance + */ + private Map mBoundListeners = new HashMap(); + /** * Cancels a pending or current upload of a remote file. * @@@ -333,26 -333,20 +353,28 @@@ upload.cancel(); } } + + + + public void clearListeners() { + mBoundListeners.clear(); + } + + + /** - * Returns True when the file described by 'file' is being uploaded to the ownCloud account 'account' or waiting for it + * Returns True when the file described by 'file' is being uploaded to + * the ownCloud account 'account' or waiting for it * - * If 'file' is a directory, returns 'true' if some of its descendant - * files is downloading or waiting to download. + * If 'file' is a directory, returns 'true' if some of its descendant files is uploading or waiting to upload. * - * @param account Owncloud account where the remote file will be stored. - * @param file A file that could be in the queue of pending uploads + * @param account Owncloud account where the remote file will be stored. + * @param file A file that could be in the queue of pending uploads */ public boolean isUploading(Account account, OCFile file) { - if (account == null || file == null) return false; + if (account == null || file == null) + return false; String targetKey = buildRemoteName(account, file); synchronized (mPendingUploads) { if (file.isDirectory()) { @@@ -368,68 -362,20 +390,69 @@@ } } } + + + /** + * Adds a listener interested in the progress of the upload for a concrete file. + * + * @param listener Object to notify about progress of transfer. + * @param account ownCloud account holding the file of interest. + * @param file {@link OCfile} of interest for listener. + */ + public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) { + if (account == null || file == null || listener == null) return; + String targetKey = buildRemoteName(account, file); + mBoundListeners.put(targetKey, listener); + } + + + + /** + * Removes a listener interested in the progress of the upload for a concrete file. + * + * @param listener Object to notify about progress of transfer. + * @param account ownCloud account holding the file of interest. + * @param file {@link OCfile} of interest for listener. + */ + public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) { + if (account == null || file == null || listener == null) return; + String targetKey = buildRemoteName(account, file); + if (mBoundListeners.get(targetKey) == listener) { + mBoundListeners.remove(targetKey); + } + } + + + @Override + public void onTransferProgress(long progressRate) { + // old way, should not be in use any more + } + + + @Override + public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, + String fileName) { + String key = buildRemoteName(mCurrentUpload.getAccount(), mCurrentUpload.getFile()); + OnDatatransferProgressListener boundListener = mBoundListeners.get(key); + if (boundListener != null) { + boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName); + } + } + } - - - - - /** - * Upload worker. Performs the pending uploads in the order they were requested. + + /** + * Upload worker. Performs the pending uploads in the order they were + * requested. * - * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. + * Created with the Looper of a new thread, started in + * {@link FileUploader#onCreate()}. */ private static class ServiceHandler extends Handler { - // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak + // don't make it a final class, and don't remove the static ; lint will + // warn about a possible memory leak FileUploader mService; + public ServiceHandler(Looper looper, FileUploader service) { super(looper); if (service == null) @@@ -569,19 -520,27 +597,26 @@@ file.setMimetype(we.contentType()); file.setModificationTimestamp(we.modifiedTimestamp()); file.setModificationTimestampAtLastSyncForData(we.modifiedTimestamp()); - // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where - // available + // file.setEtag(mCurrentUpload.getEtag()); // TODO Etag, where available } - - + private boolean checkAndFixInstantUploadDirectory(FileDataStorageManager storageManager) { - OCFile instantUploadDir = storageManager.getFileByPath(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR); + OCFile instantUploadDir = storageManager.getFileByPath(InstantUploadService.INSTANT_UPLOAD_DIR); if (instantUploadDir == null) { - // first instant upload in the account, or never account not synchronized after the remote InstantUpload folder was created - OCFile newDir = new OCFile(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR); + // first instant upload in the account, or never account not + // synchronized after the remote InstantUpload folder was created + OCFile newDir = new OCFile(InstantUploadService.INSTANT_UPLOAD_DIR); newDir.setMimetype("DIR"); - newDir.setParentId(storageManager.getFileByPath(OCFile.PATH_SEPARATOR).getFileId()); - storageManager.saveFile(newDir); - return true; + OCFile path = storageManager.getFileByPath(OCFile.PATH_SEPARATOR); + + if (path != null) { + newDir.setParentId(path.getFileId()); + storageManager.saveFile(newDir); + return true; + } else { + return false; + } + } return false; } @@@ -631,28 -595,25 +671,31 @@@ /** * Creates a status notification to show the upload progress * - * @param upload Upload operation starting. + * @param upload Upload operation starting. */ + @SuppressWarnings("deprecation") private void notifyUploadStart(UploadFileOperation upload) { - /// create status notification with a progress bar + // / create status notification with a progress bar mLastPercent = 0; - mNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_in_progress_ticker), System.currentTimeMillis()); + mNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_in_progress_ticker), + System.currentTimeMillis()); mNotification.flags |= Notification.FLAG_ONGOING_EVENT; mDefaultNotificationContentView = mNotification.contentView; - mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout); + mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), + R.layout.progressbar_layout); mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, false); - mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName())); + mNotification.contentView.setTextViewText(R.id.status_text, + String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName())); mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon); - - // / includes a pending intent in the notification showing the details - // view of the file - Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + + /// includes a pending intent in the notification showing the details view of the file + Intent showDetailsIntent = null; + if (PreviewImageFragment.canBePreviewed(upload.getFile())) { + showDetailsIntent = new Intent(this, PreviewImageActivity.class); + } else { + showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS); + } showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, upload.getFile()); showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, upload.getAccount()); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); @@@ -689,29 -650,28 +732,33 @@@ /** * Updates the status notification with the result of an upload operation. * - * @param uploadResult Result of the upload operation. - * @param upload Finished upload operation + * @param uploadResult Result of the upload operation. + * @param upload Finished upload operation */ private void notifyUploadResult(RemoteOperationResult uploadResult, UploadFileOperation upload) { + Log.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode()); if (uploadResult.isCancelled()) { - /// cancelled operation -> silent removal of progress notification + // / cancelled operation -> silent removal of progress notification mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker); - + } else if (uploadResult.isSuccess()) { - /// success -> silent update of progress notification to success message - mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove the ongoing flag + // / success -> silent update of progress notification to success + // message + mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove + // the + // ongoing + // flag mNotification.flags |= Notification.FLAG_AUTO_CANCEL; mNotification.contentView = mDefaultNotificationContentView; - - // / includes a pending intent in the notification showing the - // details view of the file - Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + + /// includes a pending intent in the notification showing the details view of the file + Intent showDetailsIntent = null; + if (PreviewImageFragment.canBePreviewed(upload.getFile())) { + showDetailsIntent = new Intent(this, PreviewImageActivity.class); + } else { + showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS); + } showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, upload.getFile()); showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, upload.getAccount()); showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); diff --cc src/com/owncloud/android/operations/UploadFileOperation.java index 55871eaf,5bf9cc06..0dfb72c3 --- a/src/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/com/owncloud/android/operations/UploadFileOperation.java @@@ -30,14 -30,13 +30,17 @@@ import java.util.concurrent.atomic.Atom import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.http.HttpStatus; + import android.accounts.Account; + import android.util.Log; + import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.network.ProgressiveDataTransferer; +import com.owncloud.android.operations.RemoteOperation; +import com.owncloud.android.operations.RemoteOperationResult; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.utils.FileStorageUtils; @@@ -154,25 -147,11 +157,25 @@@ public class UploadFileOperation extend public Set getDataTransferListeners() { return mDataTransferListeners; } - - public void addDatatransferProgressListener(OnDatatransferProgressListener listener) { - mDataTransferListeners.add(listener); + + public void addDatatransferProgressListener (OnDatatransferProgressListener listener) { + synchronized (mDataTransferListeners) { + mDataTransferListeners.add(listener); + } + if (mEntity != null) { + ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener); + } + } + + public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) { + synchronized (mDataTransferListeners) { + mDataTransferListeners.remove(listener); + } + if (mEntity != null) { + ((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener); + } } - + @Override protected RemoteOperationResult run(WebdavClient client) { RemoteOperationResult result = null; @@@ -349,16 -348,15 +372,17 @@@ int status = -1; try { File f = new File(mFile.getStoragePath()); - FileRequestEntity entity = new FileRequestEntity(f, getMimeType()); - entity.addOnDatatransferProgressListeners(mDataTransferListeners); - mPutMethod.setRequestEntity(entity); + mEntity = new FileRequestEntity(f, getMimeType()); + synchronized (mDataTransferListeners) { + ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners); + } + mPutMethod.setRequestEntity(mEntity); status = client.executeMethod(mPutMethod); client.exhaustResponse(mPutMethod.getResponseBodyAsStream()); - + } finally { - mPutMethod.releaseConnection(); // let the connection available for other methods + mPutMethod.releaseConnection(); // let the connection available for + // other methods } return status; } diff --cc src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 97660e7d,46ed65e6..ca0ff010 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@@ -1,1460 -1,1309 +1,1468 @@@ -/* 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 as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 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 . - * - */ +/* 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 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 java.io.File; + +import android.accounts.Account; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.app.AlertDialog.Builder; +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources.NotFoundException; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.provider.MediaStore; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.ActionBar.OnNavigationListener; +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.Window; +import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; +import com.owncloud.android.datamodel.DataStorageManager; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.services.FileDownloader; +import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; +import com.owncloud.android.files.services.FileObserverService; +import com.owncloud.android.files.services.FileUploader; +import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; +import com.owncloud.android.network.OwnCloudClientUtils; +import com.owncloud.android.operations.OnRemoteOperationListener; +import com.owncloud.android.operations.RemoteOperation; +import com.owncloud.android.operations.RemoteOperationResult; +import com.owncloud.android.operations.RemoveFileOperation; +import com.owncloud.android.operations.RenameFileOperation; +import com.owncloud.android.operations.SynchronizeFileOperation; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.syncadapter.FileSyncService; +import com.owncloud.android.ui.dialog.ChangelogDialog; +import com.owncloud.android.ui.dialog.SslValidatorDialog; +import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; +import com.owncloud.android.ui.fragment.FileDetailFragment; +import com.owncloud.android.ui.fragment.FileFragment; +import com.owncloud.android.ui.fragment.OCFileListFragment; +import com.owncloud.android.ui.preview.PreviewImageActivity; +import com.owncloud.android.ui.preview.PreviewImageFragment; +import com.owncloud.android.ui.preview.PreviewMediaFragment; + +import com.owncloud.android.R; +import eu.alefzero.webdav.WebdavClient; + +/** + * Displays, what files the user has available in his ownCloud. + * + * @author Bartek Przybylski + * @author David A. Velasco + */ + +public class FileDisplayActivity extends SherlockFragmentActivity implements + OCFileListFragment.ContainerActivity, FileFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener { + + private ArrayAdapter mDirectories; + private OCFile mCurrentDir = null; + private OCFile mCurrentFile = null; + + private DataStorageManager mStorageManager; + private SyncBroadcastReceiver mSyncBroadcastReceiver; + private UploadFinishReceiver mUploadFinishReceiver; + private DownloadFinishReceiver mDownloadFinishReceiver; + private FileDownloaderBinder mDownloaderBinder = null; + private FileUploaderBinder mUploaderBinder = null; + private ServiceConnection mDownloadConnection = null, mUploadConnection = null; + private RemoteOperationResult mLastSslUntrustedServerResult = null; + + private OCFileListFragment mFileList; + + private boolean mDualPane; + + private static final int DIALOG_SETUP_ACCOUNT = 0; + private static final int DIALOG_CREATE_DIR = 1; + private static final int DIALOG_ABOUT_APP = 2; + public static final int DIALOG_SHORT_WAIT = 3; + private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4; + private static final int DIALOG_SSL_VALIDATOR = 5; + private static final int DIALOG_CERT_NOT_SAVED = 6; + private static final String DIALOG_CHANGELOG_TAG = "DIALOG_CHANGELOG"; + + + private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1; + private static final int ACTION_SELECT_MULTIPLE_FILES = 2; + + private static final String TAG = "FileDisplayActivity"; + + private static int[] mMenuIdentifiersToPatch = {R.id.action_about_app}; + + private OCFile mWaitingToPreview; + private Handler mHandler; + + + @Override + public void onCreate(Bundle savedInstanceState) { + Log.d(getClass().toString(), "onCreate() start"); + super.onCreate(savedInstanceState); + + /// Load of parameters from received intent + mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); // no check necessary, mCurrenDir == null if the parameter is not in the intent + Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT); + if (account != null) + AccountUtils.setCurrentOwnCloudAccount(this, account.name); + + /// Load of saved instance state: keep this always before initDataFromCurrentAccount() + if(savedInstanceState != null) { + // TODO - test if savedInstanceState should take precedence over file in the intent ALWAYS (now), NEVER, or SOME TIMES + mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE); + mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW); + + } else { + mWaitingToPreview = null; + } + + if (!AccountUtils.accountsAreSetup(this)) { + /// no account available: FORCE ACCOUNT CREATION + mStorageManager = null; + createFirstAccount(); + + } else { /// at least an account is available + + initDataFromCurrentAccount(); // it checks mCurrentDir and mCurrentFile with the current account + + } + + mUploadConnection = new ListServiceConnection(); + mDownloadConnection = new ListServiceConnection(); + bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE); + bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE); + + // PIN CODE request ; best location is to decide, let's try this first + if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) { + requestPinCode(); + } + + // file observer + Intent observer_intent = new Intent(this, FileObserverService.class); + observer_intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST); + startService(observer_intent); + + + /// USER INTERFACE + requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); + + // Drop-down navigation + mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); + OCFile currFile = mCurrentDir; + while(currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) { + mDirectories.add(currFile.getFileName()); + currFile = mStorageManager.getFileById(currFile.getParentId()); + } + mDirectories.add(OCFile.PATH_SEPARATOR); + + // Inflate and set the layout view + setContentView(R.layout.files); + mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + mDualPane = (findViewById(R.id.file_details_container) != null); + if (mDualPane) { + initFileDetailsInDualPane(); + } else { + // quick patchES to fix problem in turn from landscape to portrait, when a file is selected in the right pane + // TODO serious refactorization in activities and fragments providing file browsing and handling + if (mCurrentFile != null) { + onFileClick(mCurrentFile); + mCurrentFile = null; + } + Fragment rightPanel = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (rightPanel != null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.remove(rightPanel); + transaction.commit(); + } + } + + // Action bar setup + ActionBar actionBar = getSupportActionBar(); + actionBar.setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation + actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getParentId() != 0); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + actionBar.setListNavigationCallbacks(mDirectories, this); + setSupportProgressBarIndeterminateVisibility(false); // always AFTER setContentView(...) ; to workaround bug in its implementation + + + // show changelog, if needed + showChangeLog(); + + Log.d(getClass().toString(), "onCreate() end"); + } + + + /** + * Shows a dialog with the change log of the current version after each app update + * + * TODO make it permanent; by now, only to advice the workaround app for 4.1.x + */ + private void showChangeLog() { + if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN) { + final String KEY_VERSION = "version"; + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + int currentVersionNumber = 0; + int savedVersionNumber = sharedPref.getInt(KEY_VERSION, 0); + try { + PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0); + currentVersionNumber = pi.versionCode; + } catch (Exception e) {} + + if (currentVersionNumber > savedVersionNumber) { + ChangelogDialog.newInstance(true).show(getSupportFragmentManager(), DIALOG_CHANGELOG_TAG); + Editor editor = sharedPref.edit(); + editor.putInt(KEY_VERSION, currentVersionNumber); + editor.commit(); + } + } + } + + + /** + * Launches the account creation activity. To use when no ownCloud account is available + */ + private void createFirstAccount() { + Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); + intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); + startActivity(intent); // the new activity won't be created until this.onStart() and this.onResume() are finished; + } + + + /** + * Load of state dependent of the existence of an ownCloud account + */ + private void initDataFromCurrentAccount() { + /// Storage manager initialization - access to local database + mStorageManager = new FileDataStorageManager( + AccountUtils.getCurrentOwnCloudAccount(this), + getContentResolver()); + + /// Check if mCurrentDir is a directory + if(mCurrentDir != null && !mCurrentDir.isDirectory()) { + mCurrentFile = mCurrentDir; + mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId()); + } + + /// Check if mCurrentDir and mCurrentFile are in the current account, and update them + if (mCurrentDir != null) { + mCurrentDir = mStorageManager.getFileByPath(mCurrentDir.getRemotePath()); // mCurrentDir == null if it is not in the current account + } + if (mCurrentFile != null) { + if (mCurrentFile.fileExists()) { + mCurrentFile = mStorageManager.getFileByPath(mCurrentFile.getRemotePath()); // mCurrentFile == null if it is not in the current account + } // else : keep mCurrentFile with the received value; this is currently the case of an upload in progress, when the user presses the status notification in a landscape tablet + } + + /// Default to root if mCurrentDir was not found + if (mCurrentDir == null) { + mCurrentDir = mStorageManager.getFileByPath("/"); // will be NULL if the database was never synchronized + } + } + + + private void initFileDetailsInDualPane() { + if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + if (mCurrentFile != null) { + if (PreviewMediaFragment.canBePreviewed(mCurrentFile)) { + if (mCurrentFile.isDown()) { + transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + } else { + transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + mWaitingToPreview = mCurrentFile; + } + } else { + transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + } + mCurrentFile = null; + + } else { + transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment + } + transaction.commit(); + } + } + + + @Override + public void onDestroy() { + super.onDestroy(); + if (mDownloadConnection != null) + unbindService(mDownloadConnection); + if (mUploadConnection != null) + unbindService(mUploadConnection); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getSherlock().getMenuInflater(); + inflater.inflate(R.menu.main_menu, menu); + + patchHiddenAccents(menu); + + return true; + } + + /** + * Workaround for this: http://code.google.com/p/android/issues/detail?id=3974 + * + * @param menu Menu to patch + */ + private void patchHiddenAccents(Menu menu) { + for (int i = 0; i < mMenuIdentifiersToPatch.length ; i++) { + MenuItem aboutItem = menu.findItem(mMenuIdentifiersToPatch[i]); + if (aboutItem != null && aboutItem.getIcon() instanceof BitmapDrawable) { + // Clip off the bottom three (density independent) pixels of transparent padding + Bitmap original = ((BitmapDrawable) aboutItem.getIcon()).getBitmap(); + float scale = getResources().getDisplayMetrics().density; + int clippedHeight = (int) (original.getHeight() - (3 * scale)); + Bitmap scaled = Bitmap.createBitmap(original, 0, 0, original.getWidth(), clippedHeight); + aboutItem.setIcon(new BitmapDrawable(getResources(), scaled)); + } + } + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + boolean retval = true; + switch (item.getItemId()) { + case R.id.action_create_dir: { + showDialog(DIALOG_CREATE_DIR); + break; + } + case R.id.action_sync_account: { + startSynchronization(); + break; + } + case R.id.action_upload: { + showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE); + break; + } + case R.id.action_settings: { + Intent settingsIntent = new Intent(this, Preferences.class); + startActivity(settingsIntent); + break; + } + case R.id.action_about_app: { + showDialog(DIALOG_ABOUT_APP); + break; + } + case android.R.id.home: { + if(mCurrentDir != null && mCurrentDir.getParentId() != 0){ + onBackPressed(); + } + break; + } + default: + retval = super.onOptionsItemSelected(item); + } + return retval; + } + + private void startSynchronization() { + ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE); // cancel the current synchronizations of any ownCloud account + Bundle bundle = new Bundle(); + bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + ContentResolver.requestSync( + AccountUtils.getCurrentOwnCloudAccount(this), + AccountAuthenticator.AUTH_TOKEN_TYPE, bundle); + } + + + @Override + public boolean onNavigationItemSelected(int itemPosition, long itemId) { + int i = itemPosition; + while (i-- != 0) { + onBackPressed(); + } + // the next operation triggers a new call to this method, but it's necessary to + // ensure that the name exposed in the action bar is the current directory when the + // user selected it in the navigation list + if (itemPosition != 0) + getSupportActionBar().setSelectedNavigationItem(0); + return true; + } + + /** + * Called, when the user selected something for uploading + */ + public void onActivityResult(int requestCode, int resultCode, Intent data) { + + if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) { + requestSimpleUpload(data, resultCode); + + } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) { + requestMultipleUpload(data, resultCode); + + } + } + + private void requestMultipleUpload(Intent data, int resultCode) { + String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES); + if (filePaths != null) { + String[] remotePaths = new String[filePaths.length]; + String remotePathBase = ""; + for (int j = mDirectories.getCount() - 2; j >= 0; --j) { + remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j); + } + if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR)) + remotePathBase += OCFile.PATH_SEPARATOR; + for (int j = 0; j< remotePaths.length; j++) { + remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName(); + } + + Intent i = new Intent(this, FileUploader.class); + i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths); + i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths); + i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES); + if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE) + i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE); + startService(i); + + } else { + Log.d("FileDisplay", "User clicked on 'Update' with no selection"); + Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG); + t.show(); + return; + } + } + + + private void requestSimpleUpload(Intent data, int resultCode) { + String filepath = null; + try { + Uri selectedImageUri = data.getData(); + + String filemanagerstring = selectedImageUri.getPath(); + String selectedImagePath = getPath(selectedImageUri); + + if (selectedImagePath != null) + filepath = selectedImagePath; + else + filepath = filemanagerstring; + + } catch (Exception e) { + Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e); + e.printStackTrace(); + + } finally { + if (filepath == null) { + Log.e("FileDisplay", "Couldnt resolve path to file"); + Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG); + t.show(); + return; + } + } + + Intent i = new Intent(this, FileUploader.class); + i.putExtra(FileUploader.KEY_ACCOUNT, + AccountUtils.getCurrentOwnCloudAccount(this)); + String remotepath = new String(); + for (int j = mDirectories.getCount() - 2; j >= 0; --j) { + remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j); + } + if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) + remotepath += OCFile.PATH_SEPARATOR; + remotepath += new File(filepath).getName(); + + i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath); + i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath); + i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE); + if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE) + i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE); + startService(i); + } + + + @Override + public void onBackPressed() { + if (mDirectories.getCount() <= 1) { + finish(); + return; + } + popDirname(); + mFileList.onNavigateUp(); + mCurrentDir = mFileList.getCurrentFile(); + + if (mDualPane) { + // Resets the FileDetailsFragment on Tablets so that it always displays + Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment + transaction.commit(); + } + } + + if(mCurrentDir.getParentId() == 0){ + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(false); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved + Log.d(getClass().toString(), "onSaveInstanceState() start"); + super.onSaveInstanceState(outState); + outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir); + if (mDualPane) { + FileFragment fragment = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (fragment != null) { + OCFile file = fragment.getFile(); + if (file != null) { + outState.putParcelable(FileDetailFragment.EXTRA_FILE, file); + } + } + } + outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview); + Log.d(getClass().toString(), "onSaveInstanceState() end"); + } + + @Override + public void onResume() { + Log.d(getClass().toString(), "onResume() start"); + super.onResume(); + + if (AccountUtils.accountsAreSetup(this)) { + + if (mStorageManager == null) { + // this is necessary for handling the come back to FileDisplayActivity when the first ownCloud account is created + initDataFromCurrentAccount(); + if (mDualPane) { + initFileDetailsInDualPane(); + } + } + + // Listen for sync messages + IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE); + mSyncBroadcastReceiver = new SyncBroadcastReceiver(); + registerReceiver(mSyncBroadcastReceiver, syncIntentFilter); + + // Listen for upload messages + IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); + mUploadFinishReceiver = new UploadFinishReceiver(); + registerReceiver(mUploadFinishReceiver, uploadIntentFilter); + + // Listen for download messages + IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE); + downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE); + mDownloadFinishReceiver = new DownloadFinishReceiver(); + registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); + + // List current directory + mFileList.listDirectory(mCurrentDir); // TODO we should find the way to avoid the need of this (maybe it's not necessary yet; to check) + + } else { + + mStorageManager = null; // an invalid object will be there if all the ownCloud accounts are removed + showDialog(DIALOG_SETUP_ACCOUNT); + + } + Log.d(getClass().toString(), "onResume() end"); + } + + + @Override + public void onPause() { + Log.d(getClass().toString(), "onPause() start"); + super.onPause(); + if (mSyncBroadcastReceiver != null) { + unregisterReceiver(mSyncBroadcastReceiver); + mSyncBroadcastReceiver = null; + } + if (mUploadFinishReceiver != null) { + unregisterReceiver(mUploadFinishReceiver); + mUploadFinishReceiver = null; + } + if (mDownloadFinishReceiver != null) { + unregisterReceiver(mDownloadFinishReceiver); + mDownloadFinishReceiver = null; + } + if (!AccountUtils.accountsAreSetup(this)) { + dismissDialog(DIALOG_SETUP_ACCOUNT); + } + + Log.d(getClass().toString(), "onPause() end"); + } + + + @Override + protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { + if (id == DIALOG_SSL_VALIDATOR && mLastSslUntrustedServerResult != null) { + ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult); + } + } + + + @Override + protected Dialog onCreateDialog(int id) { + Dialog dialog = null; + AlertDialog.Builder builder; + switch (id) { + case DIALOG_SETUP_ACCOUNT: { + builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.main_tit_accsetup); + builder.setMessage(R.string.main_wrn_accsetup); + builder.setCancelable(false); + builder.setPositiveButton(android.R.string.ok, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + createFirstAccount(); + dialog.dismiss(); + } + }); + String message = String.format(getString(R.string.common_exit), getString(R.string.app_name)); + builder.setNegativeButton(message, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + finish(); + } + }); + //builder.setNegativeButton(android.R.string.cancel, this); + dialog = builder.create(); + break; + } + case DIALOG_ABOUT_APP: { + builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.about_title)); + PackageInfo pkg; + try { + pkg = getPackageManager().getPackageInfo(getPackageName(), 0); + builder.setMessage(String.format(getString(R.string.about_message), getString(R.string.app_name), pkg.versionName)); + builder.setIcon(android.R.drawable.ic_menu_info_details); + dialog = builder.create(); + } catch (NameNotFoundException e) { + builder = null; + dialog = null; + Log.e(TAG, "Error while showing about dialog", e); + } + break; + } + case DIALOG_CREATE_DIR: { + builder = new Builder(this); + final EditText dirNameInput = new EditText(getBaseContext()); + builder.setView(dirNameInput); + builder.setTitle(R.string.uploader_info_dirname); + int typed_color = getResources().getColor(R.color.setup_text_typed); + dirNameInput.setTextColor(typed_color); + builder.setPositiveButton(android.R.string.ok, + new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String directoryName = dirNameInput.getText().toString(); + if (directoryName.trim().length() == 0) { + dialog.cancel(); + return; + } + + // Figure out the path where the dir needs to be created + String path; + if (mCurrentDir == null) { + // this is just a patch; we should ensure that mCurrentDir never is null + if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) { + OCFile file = new OCFile(OCFile.PATH_SEPARATOR); + mStorageManager.saveFile(file); + } + mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); + } + path = FileDisplayActivity.this.mCurrentDir.getRemotePath(); + + // Create directory + path += directoryName + OCFile.PATH_SEPARATOR; + Thread thread = new Thread(new DirectoryCreator(path, AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler())); + thread.start(); + + dialog.dismiss(); + + showDialog(DIALOG_SHORT_WAIT); + } + }); + builder.setNegativeButton(R.string.common_cancel, + new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + dialog = builder.create(); + break; + } + case DIALOG_SHORT_WAIT: { + ProgressDialog working_dialog = new ProgressDialog(this); + working_dialog.setMessage(getResources().getString( + R.string.wait_a_moment)); + working_dialog.setIndeterminate(true); + working_dialog.setCancelable(false); + dialog = working_dialog; + break; + } + case DIALOG_CHOOSE_UPLOAD_SOURCE: { - final String [] items = { getString(R.string.actionbar_upload_files), - getString(R.string.actionbar_upload_from_apps) }; ++ final String[] items = { getString(R.string.actionbar_upload_files), ++ getString(R.string.actionbar_upload_from_apps), ++ getString(R.string.actionbar_failed_instant_upload) }; + builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.actionbar_upload); + builder.setItems(items, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + if (item == 0) { - //if (!mDualPane) { - Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class); - action.putExtra(UploadFilesActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this)); - startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES); - //} else { - // TODO create and handle new fragment LocalFileListFragment - //} ++ // if (!mDualPane) { ++ Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class); ++ action.putExtra(UploadFilesActivity.EXTRA_ACCOUNT, ++ AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this)); ++ startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES); ++ // } else { ++ // TODO create and handle new fragment ++ // LocalFileListFragment ++ // } + } else if (item == 1) { + Intent action = new Intent(Intent.ACTION_GET_CONTENT); - action = action.setType("*/*") - .addCategory(Intent.CATEGORY_OPENABLE); - startActivityForResult( - Intent.createChooser(action, getString(R.string.upload_chooser_title)), ++ action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE); ++ startActivityForResult(Intent.createChooser(action, getString(R.string.upload_chooser_title)), + ACTION_SELECT_CONTENT_FROM_APPS); ++ } else if (item == 2) { ++ Account account = AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this); ++ Intent action = new Intent(FileDisplayActivity.this, InstantUploadActivity.class); ++ action.putExtra(FileUploader.KEY_ACCOUNT, account); ++ startActivity(action); + } + } + }); + dialog = builder.create(); + break; + } + case DIALOG_SSL_VALIDATOR: { + dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this); + break; + } + case DIALOG_CERT_NOT_SAVED: { + builder = new AlertDialog.Builder(this); + builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved)); + builder.setCancelable(false); + builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + }; + }); + dialog = builder.create(); + break; + } + default: + dialog = null; + } + + return dialog; + } + + + /** + * Translates a content URI of an image to a physical path + * on the disk + * @param uri The URI to resolve + * @return The path to the image or null if it could not be found + */ + public String getPath(Uri uri) { + String[] projection = { MediaStore.Images.Media.DATA }; + Cursor cursor = managedQuery(uri, projection, null, null, null); + if (cursor != null) { + int column_index = cursor + .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + return cursor.getString(column_index); + } + return null; + } + + /** + * Pushes a directory to the drop down list + * @param directory to push + * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false. + */ + public void pushDirname(OCFile directory) { + if(!directory.isDirectory()){ + throw new IllegalArgumentException("Only directories may be pushed!"); + } + mDirectories.insert(directory.getFileName(), 0); + mCurrentDir = directory; + } + + /** + * Pops a directory name from the drop down list + * @return True, unless the stack is empty + */ + public boolean popDirname() { + mDirectories.remove(mDirectories.getItem(0)); + return !mDirectories.isEmpty(); + } + + private class DirectoryCreator implements Runnable { + private String mTargetPath; + private Account mAccount; + private Handler mHandler; + + public DirectoryCreator(String targetPath, Account account, Handler handler) { + mTargetPath = targetPath; + mAccount = account; + mHandler = handler; + } + + @Override + public void run() { + WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); + boolean created = wdc.createDirectory(mTargetPath); + if (created) { + mHandler.post(new Runnable() { + @Override + public void run() { + dismissDialog(DIALOG_SHORT_WAIT); + + // Save new directory in local database + OCFile newDir = new OCFile(mTargetPath); + newDir.setMimetype("DIR"); + newDir.setParentId(mCurrentDir.getFileId()); + mStorageManager.saveFile(newDir); + + // Display the new folder right away + mFileList.listDirectory(); + } + }); + + } else { + mHandler.post(new Runnable() { + @Override + public void run() { + dismissDialog(DIALOG_SHORT_WAIT); + try { + Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); + msg.show(); + + } catch (NotFoundException e) { + Log.e(TAG, "Error while trying to show fail message " , e); + } + } + }); + } + } + + } + + // Custom array adapter to override text colors + private class CustomArrayAdapter extends ArrayAdapter { + + public CustomArrayAdapter(FileDisplayActivity ctx, int view) { + super(ctx, view); + } + + public View getView(int position, View convertView, ViewGroup parent) { + View v = super.getView(position, convertView, parent); + + ((TextView) v).setTextColor(getResources().getColorStateList( + android.R.color.white)); + return v; + } + + public View getDropDownView(int position, View convertView, + ViewGroup parent) { + View v = super.getDropDownView(position, convertView, parent); + + ((TextView) v).setTextColor(getResources().getColorStateList( + android.R.color.white)); + + return v; + } + + } + + private class SyncBroadcastReceiver extends BroadcastReceiver { + + /** + * {@link BroadcastReceiver} to enable syncing feedback in UI + */ + @Override + public void onReceive(Context context, Intent intent) { + boolean inProgress = intent.getBooleanExtra( + FileSyncService.IN_PROGRESS, false); + String accountName = intent + .getStringExtra(FileSyncService.ACCOUNT_NAME); + + Log.d("FileDisplay", "sync of account " + accountName + + " is in_progress: " + inProgress); + + if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) { + + String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); + + boolean fillBlankRoot = false; + if (mCurrentDir == null) { + mCurrentDir = mStorageManager.getFileByPath("/"); + fillBlankRoot = (mCurrentDir != null); + } + + if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath))) + || fillBlankRoot ) { + if (!fillBlankRoot) + mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath); + OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager() + .findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(mCurrentDir); + } + } + + setSupportProgressBarIndeterminateVisibility(inProgress); + removeStickyBroadcast(intent); + + } + + RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT); + if (synchResult != null) { + if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) { + mLastSslUntrustedServerResult = synchResult; + showDialog(DIALOG_SSL_VALIDATOR); + } + } + } + } + + + private class UploadFinishReceiver extends BroadcastReceiver { + /** + * Once the file upload has finished -> update view + * @author David A. Velasco + * {@link BroadcastReceiver} to enable upload feedback in UI + */ + @Override + public void onReceive(Context context, Intent intent) { + String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); + String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME); + boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name); + boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath())); + if (sameAccount && isDescendant) { + OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(); + } + } + } + + } + + + /** + * Class waiting for broadcast events from the {@link FielDownloader} service. + * + * Updates the UI when a download is started or finished, provided that it is relevant for the + * current folder. + */ + private class DownloadFinishReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + boolean sameAccount = isSameAccount(context, intent); + String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); + boolean isDescendant = isDescendant(downloadedRemotePath); + + if (sameAccount && isDescendant) { + updateLeftPanel(); + if (mDualPane) { + updateRightPanel(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false)); + } + } + + removeStickyBroadcast(intent); + } + + private boolean isDescendant(String downloadedRemotePath) { + return (mCurrentDir != null && downloadedRemotePath != null && downloadedRemotePath.startsWith(mCurrentDir.getRemotePath())); + } + + private boolean isSameAccount(Context context, Intent intent) { + String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); + return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)); + } + } + + + protected void updateLeftPanel() { + OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(); + } + } + + protected void updateRightPanel(String downloadEvent, String downloadedRemotePath, boolean success) { + Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + boolean waitedPreview = (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(downloadedRemotePath)); + if (fragment != null && fragment instanceof FileDetailFragment) { + FileDetailFragment detailsFragment = (FileDetailFragment) fragment; + OCFile fileInFragment = detailsFragment.getFile(); + if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) { + // the user browsed to other file ; forget the automatic preview + mWaitingToPreview = null; + + } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) { + // grant that the right panel updates the progress bar + detailsFragment.listenForTransferProgress(); + detailsFragment.updateFileDetails(true, false); + + } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) { + // update the right panel + if (success && waitedPreview) { + mWaitingToPreview = mStorageManager.getFileById(mWaitingToPreview.getFileId()); // update the file from database, for the local storage path + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mWaitingToPreview, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + transaction.commit(); + mWaitingToPreview = null; + + } else { + detailsFragment.updateFileDetails(false, (success)); + } + } + } + } + + + /** + * {@inheritDoc} + */ + @Override + public DataStorageManager getStorageManager() { + return mStorageManager; + } + + + /** + * {@inheritDoc} + */ + @Override + public void onDirectoryClick(OCFile directory) { + pushDirname(directory); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + + if (mDualPane) { + // Resets the FileDetailsFragment on Tablets so that it always displays + Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment + transaction.commit(); + } + } + } + + + /** + * {@inheritDoc} + */ + @Override + public void onFileClick(OCFile file) { + if (file != null && PreviewImageFragment.canBePreviewed(file)) { + // preview image - it handles the download, if needed + startPreviewImage(file); + + } else if (file != null && PreviewMediaFragment.canBePreviewed(file)) { + if (file.isDown()) { + // general preview + startMediaPreview(file); + + } else { + // automatic download, preview on finish + startDownloadForPreview(file); + + } + } else { + // details view + startDetails(file); + } + } + + private void startPreviewImage(OCFile file) { + Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + startActivity(showDetailsIntent); + } + + private void startMediaPreview(OCFile file) { + if (mDualPane) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new PreviewMediaFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + transaction.commit(); + + } else { + Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + startActivity(showDetailsIntent); + } + } + + private void startDownloadForPreview(OCFile file) { + if (mDualPane) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + transaction.commit(); + mWaitingToPreview = file; + requestForDownload(); + + } else { + Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + startActivity(showDetailsIntent); + } + } + + + private void startDetails(OCFile file) { + if (mDualPane && !file.isImage()) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + transaction.commit(); + } else { + Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + startActivity(showDetailsIntent); + } + } + + + /** + * {@inheritDoc} + */ + @Override + public OCFile getInitialDirectory() { + return mCurrentDir; + } + + + /** + * {@inheritDoc} + */ + @Override + public void onFileStateChanged() { + OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(); + } + } + + + /** + * {@inheritDoc} + */ + @Override + public FileDownloaderBinder getFileDownloaderBinder() { + return mDownloaderBinder; + } + + + /** + * {@inheritDoc} + */ + @Override + public FileUploaderBinder getFileUploaderBinder() { + return mUploaderBinder; + } + + + /** Defines callbacks for service binding, passed to bindService() */ + private class ListServiceConnection implements ServiceConnection { + + @Override + public void onServiceConnected(ComponentName component, IBinder service) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { + Log.d(TAG, "Download service connected"); + mDownloaderBinder = (FileDownloaderBinder) service; + if (mWaitingToPreview != null) { + requestForDownload(); + } + + } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { + Log.d(TAG, "Upload service connected"); + mUploaderBinder = (FileUploaderBinder) service; + } else { + return; + } + // a new chance to get the mDownloadBinder through getFileDownloadBinder() - THIS IS A MESS + if (mFileList != null) + mFileList.listDirectory(); + if (mDualPane) { + Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (fragment != null && fragment instanceof FileDetailFragment) { + FileDetailFragment detailFragment = (FileDetailFragment)fragment; + detailFragment.listenForTransferProgress(); + detailFragment.updateFileDetails(false, false); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName component) { + if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { + Log.d(TAG, "Download service disconnected"); + mDownloaderBinder = null; + } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { + Log.d(TAG, "Upload service disconnected"); + mUploaderBinder = null; + } + } + }; + + + + /** + * Launch an intent to request the PIN code to the user before letting him use the app + */ + private void requestPinCode() { + boolean pinStart = false; + SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + pinStart = appPrefs.getBoolean("set_pincode", false); + if (pinStart) { + Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); + i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity"); + startActivity(i); + } + } + + + @Override + public void onSavedCertificate() { + startSynchronization(); + } + + + @Override + public void onFailedSavingCertificate() { + showDialog(DIALOG_CERT_NOT_SAVED); + } + + + /** + * Updates the view associated to the activity after the finish of some operation over files + * in the current account. + * + * @param operation Removal operation performed. + * @param result Result of the removal. + */ + @Override + public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { + if (operation instanceof RemoveFileOperation) { + onRemoveFileOperationFinish((RemoveFileOperation)operation, result); + + } else if (operation instanceof RenameFileOperation) { + onRenameFileOperationFinish((RenameFileOperation)operation, result); + + } else if (operation instanceof SynchronizeFileOperation) { + onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result); + } + } + + + /** + * Updates the view associated to the activity after the finish of an operation trying to remove a + * file. + * + * @param operation Removal operation performed. + * @param result Result of the removal. + */ + private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) { + dismissDialog(DIALOG_SHORT_WAIT); + if (result.isSuccess()) { + Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG); + msg.show(); + OCFile removedFile = operation.getFile(); + if (mDualPane) { + FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (details != null && removedFile.equals(details.getFile())) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment + transaction.commit(); + } + } + if (mStorageManager.getFileById(removedFile.getParentId()).equals(mCurrentDir)) { + mFileList.listDirectory(); + } + + } else { + Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); + msg.show(); + if (result.isSslRecoverableException()) { + mLastSslUntrustedServerResult = result; + showDialog(DIALOG_SSL_VALIDATOR); + } + } + } + + /** + * Updates the view associated to the activity after the finish of an operation trying to rename a + * file. + * + * @param operation Renaming operation performed. + * @param result Result of the renaming. + */ + private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) { + dismissDialog(DIALOG_SHORT_WAIT); + OCFile renamedFile = operation.getFile(); + if (result.isSuccess()) { + if (mDualPane) { + FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (details != null && details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) { + ((FileDetailFragment) details).updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this)); + } + } + if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) { + mFileList.listDirectory(); + } + + } else { + if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) { + Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG); + msg.show(); + // TODO throw again the new rename dialog + } else { + Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG); + msg.show(); + if (result.isSslRecoverableException()) { + mLastSslUntrustedServerResult = result; + showDialog(DIALOG_SSL_VALIDATOR); + } + } + } + } + + + private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) { + dismissDialog(DIALOG_SHORT_WAIT); + OCFile syncedFile = operation.getLocalFile(); + if (!result.isSuccess()) { + if (result.getCode() == ResultCode.SYNC_CONFLICT) { + Intent i = new Intent(this, ConflictsResolveActivity.class); + i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile); + i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + startActivity(i); + + } else { + Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); + msg.show(); + } + + } else { + if (operation.transferWasRequested()) { + mFileList.listDirectory(); + onTransferStateChanged(syncedFile, true, true); + + } else { + Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); + msg.show(); + } + } + } + + + /** + * {@inheritDoc} + */ + @Override + public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) { + /*OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); + if (fileListFragment != null) { + fileListFragment.listDirectory(); + }*/ + if (mDualPane) { + FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); + if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) { + if (downloading || uploading) { + ((FileDetailFragment)details).updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this)); + } else { + ((FileDetailFragment)details).updateFileDetails(false, true); + } + } + } + } + + + @Override + public void showFragmentWithDetails(OCFile file) { + if (mDualPane) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); + transaction.commit(); + + } else { + Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); + showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); + showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS); + startActivity(showDetailsIntent); + } + } + + + private void requestForDownload() { + Account account = AccountUtils.getCurrentOwnCloudAccount(this); + if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) { + Intent i = new Intent(this, FileDownloader.class); + i.putExtra(FileDownloader.EXTRA_ACCOUNT, account); + i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview); + startService(i); + } + } + + +} + -package com.owncloud.android.ui.activity; - -import java.io.File; - -import android.accounts.Account; -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources.NotFoundException; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.preference.PreferenceManager; -import android.provider.MediaStore; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.TextView; -import android.widget.Toast; - -import com.actionbarsherlock.app.ActionBar; -import com.actionbarsherlock.app.ActionBar.OnNavigationListener; -import com.actionbarsherlock.app.SherlockFragmentActivity; -import com.actionbarsherlock.view.Menu; -import com.actionbarsherlock.view.MenuInflater; -import com.actionbarsherlock.view.MenuItem; -import com.actionbarsherlock.view.Window; -import com.owncloud.android.AccountUtils; -import com.owncloud.android.R; -import com.owncloud.android.authenticator.AccountAuthenticator; -import com.owncloud.android.datamodel.DataStorageManager; -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.files.services.FileDownloader; -import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; -import com.owncloud.android.files.services.FileObserverService; -import com.owncloud.android.files.services.FileUploader; -import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; -import com.owncloud.android.network.OwnCloudClientUtils; -import com.owncloud.android.operations.OnRemoteOperationListener; -import com.owncloud.android.operations.RemoteOperation; -import com.owncloud.android.operations.RemoteOperationResult; -import com.owncloud.android.operations.RemoteOperationResult.ResultCode; -import com.owncloud.android.operations.RemoveFileOperation; -import com.owncloud.android.operations.RenameFileOperation; -import com.owncloud.android.operations.SynchronizeFileOperation; -import com.owncloud.android.syncadapter.FileSyncService; -import com.owncloud.android.ui.dialog.ChangelogDialog; -import com.owncloud.android.ui.dialog.SslValidatorDialog; -import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; -import com.owncloud.android.ui.fragment.FileDetailFragment; -import com.owncloud.android.ui.fragment.OCFileListFragment; - -import eu.alefzero.webdav.WebdavClient; - -/** - * Displays, what files the user has available in his ownCloud. - * - * @author Bartek Przybylski - * - */ - -public class FileDisplayActivity extends SherlockFragmentActivity implements OCFileListFragment.ContainerActivity, - FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener { - - private ArrayAdapter mDirectories; - private OCFile mCurrentDir = null; - private OCFile mCurrentFile = null; - - private DataStorageManager mStorageManager; - private SyncBroadcastReceiver mSyncBroadcastReceiver; - private UploadFinishReceiver mUploadFinishReceiver; - private DownloadFinishReceiver mDownloadFinishReceiver; - private FileDownloaderBinder mDownloaderBinder = null; - private FileUploaderBinder mUploaderBinder = null; - private ServiceConnection mDownloadConnection = null, mUploadConnection = null; - private RemoteOperationResult mLastSslUntrustedServerResult = null; - - private OCFileListFragment mFileList; - - private boolean mDualPane; - - private static final int DIALOG_SETUP_ACCOUNT = 0; - private static final int DIALOG_CREATE_DIR = 1; - private static final int DIALOG_ABOUT_APP = 2; - public static final int DIALOG_SHORT_WAIT = 3; - private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4; - private static final int DIALOG_SSL_VALIDATOR = 5; - private static final int DIALOG_CERT_NOT_SAVED = 6; - private static final String DIALOG_CHANGELOG_TAG = "DIALOG_CHANGELOG"; - - - private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1; - private static final int ACTION_SELECT_MULTIPLE_FILES = 2; - private static final int ACTION_SELECT_FAILED_INSTANT_UPLOAD = 2; - - private static final String TAG = "FileDisplayActivity"; - - private static int[] mMenuIdentifiersToPatch = {R.id.about_app}; - - @Override - public void onCreate(Bundle savedInstanceState) { - Log.d(getClass().toString(), "onCreate() start"); - super.onCreate(savedInstanceState); - - /// Load of parameters from received intent - mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); // no check necessary, mCurrenDir == null if the parameter is not in the intent - Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT); - if (account != null) - AccountUtils.setCurrentOwnCloudAccount(this, account.name); - - /// Load of saved instance state: keep this always before initDataFromCurrentAccount() - if(savedInstanceState != null) { - // TODO - test if savedInstanceState should take precedence over file in the intent ALWAYS (now), NEVER, or SOME TIMES - mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE); - } - - if (!AccountUtils.accountsAreSetup(this)) { - /// no account available: FORCE ACCOUNT CREATION - mStorageManager = null; - createFirstAccount(); - - } else { // / at least an account is available - - initDataFromCurrentAccount(); // it checks mCurrentDir and - // mCurrentFile with the current - // account - - } - - mUploadConnection = new ListServiceConnection(); - mDownloadConnection = new ListServiceConnection(); - bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE); - bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE); - - // PIN CODE request ; best location is to decide, let's try this first - if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) { - requestPinCode(); - } - - // file observer - Intent observer_intent = new Intent(this, FileObserverService.class); - observer_intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST); - startService(observer_intent); - - - /// USER INTERFACE - requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); - - // Drop-down navigation - mDirectories = new CustomArrayAdapter(this, R.layout.sherlock_spinner_dropdown_item); - OCFile currFile = mCurrentDir; - while (currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) { - mDirectories.add(currFile.getFileName()); - currFile = mStorageManager.getFileById(currFile.getParentId()); - } - mDirectories.add(OCFile.PATH_SEPARATOR); - - // Inflate and set the layout view - setContentView(R.layout.files); - mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); - mDualPane = (findViewById(R.id.file_details_container) != null); - if (mDualPane) { - initFileDetailsInDualPane(); - } - - // Action bar setup - ActionBar actionBar = getSupportActionBar(); - actionBar.setHomeButtonEnabled(true); // mandatory since Android ICS, according to the official documentation - actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getParentId() != 0); - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); - actionBar.setListNavigationCallbacks(mDirectories, this); - setSupportProgressBarIndeterminateVisibility(false); // always AFTER setContentView(...) ; to workaround bug in its implementation - - - // show changelog, if needed - showChangeLog(); - - Log.d(getClass().toString(), "onCreate() end"); - } - - - /** - * Shows a dialog with the change log of the current version after each app update - * - * TODO make it permanent; by now, only to advice the workaround app for 4.1.x - */ - private void showChangeLog() { - if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN) { - final String KEY_VERSION = "version"; - SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - int currentVersionNumber = 0; - int savedVersionNumber = sharedPref.getInt(KEY_VERSION, 0); - try { - PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0); - currentVersionNumber = pi.versionCode; - } catch (Exception e) {} - - if (currentVersionNumber > savedVersionNumber) { - ChangelogDialog.newInstance(true).show(getSupportFragmentManager(), DIALOG_CHANGELOG_TAG); - Editor editor = sharedPref.edit(); - editor.putInt(KEY_VERSION, currentVersionNumber); - editor.commit(); - } - } - } - - - /** - * Launches the account creation activity. To use when no ownCloud account is available - */ - private void createFirstAccount() { - Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); - intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE }); - startActivity(intent); // the new activity won't be created until this.onStart() and this.onResume() are finished; - } - - - /** - * Load of state dependent of the existence of an ownCloud account - */ - private void initDataFromCurrentAccount() { - /// Storage manager initialization - access to local database - mStorageManager = new FileDataStorageManager( - AccountUtils.getCurrentOwnCloudAccount(this), - getContentResolver()); - - /// Check if mCurrentDir is a directory - if(mCurrentDir != null && !mCurrentDir.isDirectory()) { - mCurrentFile = mCurrentDir; - mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId()); - } - - /// Check if mCurrentDir and mCurrentFile are in the current account, and update them - if (mCurrentDir != null) { - mCurrentDir = mStorageManager.getFileByPath(mCurrentDir.getRemotePath()); // mCurrentDir == null if it is not in the current account - } - if (mCurrentFile != null) { - if (mCurrentFile.fileExists()) { - mCurrentFile = mStorageManager.getFileByPath(mCurrentFile.getRemotePath()); // mCurrentFile == null if it is not in the current account - } // else : keep mCurrentFile with the received value; this is currently the case of an upload in progress, when the user presses the status notification in a landscape tablet - } - - /// Default to root if mCurrentDir was not found - if (mCurrentDir == null) { - mCurrentDir = mStorageManager.getFileByPath("/"); // will be NULL if the database was never synchronized - } - } - - - private void initFileDetailsInDualPane() { - if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - if (mCurrentFile != null) { - transaction.replace(R.id.file_details_container, - new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), - FileDetailFragment.FTAG); // empty FileDetailFragment - mCurrentFile = null; - } else { - transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), - FileDetailFragment.FTAG); // empty FileDetailFragment - } - transaction.commit(); - } - } - - - @Override - public void onDestroy() { - super.onDestroy(); - if (mDownloadConnection != null) - unbindService(mDownloadConnection); - if (mUploadConnection != null) - unbindService(mUploadConnection); - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getSherlock().getMenuInflater(); - inflater.inflate(R.menu.menu, menu); - - patchHiddenAccents(menu); - - return true; - } - - /** - * Workaround for this: http://code.google.com/p/android/issues/detail?id=3974 - * - * @param menu Menu to patch - */ - private void patchHiddenAccents(Menu menu) { - for (int i = 0; i < mMenuIdentifiersToPatch.length ; i++) { - MenuItem aboutItem = menu.findItem(mMenuIdentifiersToPatch[i]); - if (aboutItem != null && aboutItem.getIcon() instanceof BitmapDrawable) { - // Clip off the bottom three (density independent) pixels of transparent padding - Bitmap original = ((BitmapDrawable) aboutItem.getIcon()).getBitmap(); - float scale = getResources().getDisplayMetrics().density; - int clippedHeight = (int) (original.getHeight() - (3 * scale)); - Bitmap scaled = Bitmap.createBitmap(original, 0, 0, original.getWidth(), clippedHeight); - aboutItem.setIcon(new BitmapDrawable(getResources(), scaled)); - } - } - } - - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - boolean retval = true; - switch (item.getItemId()) { - case R.id.createDirectoryItem: { - showDialog(DIALOG_CREATE_DIR); - break; - } - case R.id.startSync: { - startSynchronization(); - break; - } - case R.id.action_upload: { - showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE); - break; - } - case R.id.action_settings: { - Intent settingsIntent = new Intent(this, Preferences.class); - startActivity(settingsIntent); - break; - } - case R.id.about_app: { - showDialog(DIALOG_ABOUT_APP); - break; - } - case android.R.id.home: { - if (mCurrentDir != null && mCurrentDir.getParentId() != 0) { - onBackPressed(); - } - break; - } - default: - retval = super.onOptionsItemSelected(item); - } - return retval; - } - - private void startSynchronization() { - ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE); // cancel the current synchronizations of any ownCloud account - Bundle bundle = new Bundle(); - bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - ContentResolver.requestSync( - AccountUtils.getCurrentOwnCloudAccount(this), - AccountAuthenticator.AUTH_TOKEN_TYPE, bundle); - } - - - @Override - public boolean onNavigationItemSelected(int itemPosition, long itemId) { - int i = itemPosition; - while (i-- != 0) { - onBackPressed(); - } - // the next operation triggers a new call to this method, but it's necessary to - // ensure that the name exposed in the action bar is the current directory when the - // user selected it in the navigation list - if (itemPosition != 0) - getSupportActionBar().setSelectedNavigationItem(0); - return true; - } - - /** - * Called, when the user selected something for uploading - */ - public void onActivityResult(int requestCode, int resultCode, Intent data) { - - if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS - && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) { - requestSimpleUpload(data, resultCode); - - } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES - && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) { - requestMultipleUpload(data, resultCode); - - } - } - - private void requestMultipleUpload(Intent data, int resultCode) { - String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES); - if (filePaths != null) { - String[] remotePaths = new String[filePaths.length]; - String remotePathBase = ""; - for (int j = mDirectories.getCount() - 2; j >= 0; --j) { - remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j); - } - if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR)) - remotePathBase += OCFile.PATH_SEPARATOR; - for (int j = 0; j < remotePaths.length; j++) { - remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName(); - } - - Intent i = new Intent(this, FileUploader.class); - i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); - i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths); - i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths); - i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES); - if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE) - i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE); - startService(i); - - } else { - Log.d("FileDisplay", "User clicked on 'Update' with no selection"); - Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG); - t.show(); - return; - } - } - - - private void requestSimpleUpload(Intent data, int resultCode) { - String filepath = null; - try { - Uri selectedImageUri = data.getData(); - - String filemanagerstring = selectedImageUri.getPath(); - String selectedImagePath = getPath(selectedImageUri); - - if (selectedImagePath != null) - filepath = selectedImagePath; - else - filepath = filemanagerstring; - - } catch (Exception e) { - Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e); - e.printStackTrace(); - - } finally { - if (filepath == null) { - Log.e("FileDisplay", "Couldnt resolve path to file"); - Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG); - t.show(); - return; - } - } - - Intent i = new Intent(this, FileUploader.class); - i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); - String remotepath = new String(); - for (int j = mDirectories.getCount() - 2; j >= 0; --j) { - remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j); - } - if (!remotepath.endsWith(OCFile.PATH_SEPARATOR)) - remotepath += OCFile.PATH_SEPARATOR; - remotepath += new File(filepath).getName(); - - i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath); - i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath); - i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE); - if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE) - i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE); - startService(i); - } - - - @Override - public void onBackPressed() { - if (mDirectories.getCount() <= 1) { - finish(); - return; - } - popDirname(); - mFileList.onNavigateUp(); - mCurrentDir = mFileList.getCurrentFile(); - - if (mDualPane) { - // Resets the FileDetailsFragment on Tablets so that it always - // displays - FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag( - FileDetailFragment.FTAG); - if (fileDetails != null && !fileDetails.isEmpty()) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.remove(fileDetails); - transaction.add(R.id.file_details_container, new FileDetailFragment(null, null), - FileDetailFragment.FTAG); - transaction.commit(); - } - } - - if (mCurrentDir.getParentId() == 0) { - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(false); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved - Log.d(getClass().toString(), "onSaveInstanceState() start"); - super.onSaveInstanceState(outState); - outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir); - if (mDualPane) { - FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); - if (fragment != null) { - OCFile file = fragment.getDisplayedFile(); - if (file != null) { - outState.putParcelable(FileDetailFragment.EXTRA_FILE, file); - } - } - } - Log.d(getClass().toString(), "onSaveInstanceState() end"); - } - - @Override - protected void onResume() { - Log.d(getClass().toString(), "onResume() start"); - super.onResume(); - - if (AccountUtils.accountsAreSetup(this)) { - - if (mStorageManager == null) { - // this is necessary for handling the come back to FileDisplayActivity when the first ownCloud account is created - initDataFromCurrentAccount(); - if (mDualPane) { - initFileDetailsInDualPane(); - } - } - - // Listen for sync messages - IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE); - mSyncBroadcastReceiver = new SyncBroadcastReceiver(); - registerReceiver(mSyncBroadcastReceiver, syncIntentFilter); - - // Listen for upload messages - IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE); - mUploadFinishReceiver = new UploadFinishReceiver(); - registerReceiver(mUploadFinishReceiver, uploadIntentFilter); - - // Listen for download messages - IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE); - mDownloadFinishReceiver = new DownloadFinishReceiver(); - registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); - - // List current directory - mFileList.listDirectory(mCurrentDir); // TODO we should find the way to avoid the need of this (maybe it's not necessary yet; to check) - - } else { - - mStorageManager = null; // an invalid object will be there if all the ownCloud accounts are removed - showDialog(DIALOG_SETUP_ACCOUNT); - - } - Log.d(getClass().toString(), "onResume() end"); - } - - - @Override - protected void onPause() { - Log.d(getClass().toString(), "onPause() start"); - super.onPause(); - if (mSyncBroadcastReceiver != null) { - unregisterReceiver(mSyncBroadcastReceiver); - mSyncBroadcastReceiver = null; - } - if (mUploadFinishReceiver != null) { - unregisterReceiver(mUploadFinishReceiver); - mUploadFinishReceiver = null; - } - if (mDownloadFinishReceiver != null) { - unregisterReceiver(mDownloadFinishReceiver); - mDownloadFinishReceiver = null; - } - if (!AccountUtils.accountsAreSetup(this)) { - dismissDialog(DIALOG_SETUP_ACCOUNT); - } - - Log.d(getClass().toString(), "onPause() end"); - } - - - @Override - protected void onPrepareDialog(int id, Dialog dialog, Bundle args) { - if (id == DIALOG_SSL_VALIDATOR && mLastSslUntrustedServerResult != null) { - ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult); - } - } - - - @Override - protected Dialog onCreateDialog(int id) { - Dialog dialog = null; - AlertDialog.Builder builder; - switch (id) { - case DIALOG_SETUP_ACCOUNT: { - builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.main_tit_accsetup); - builder.setMessage(R.string.main_wrn_accsetup); - builder.setCancelable(false); - builder.setPositiveButton(android.R.string.ok, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - createFirstAccount(); - dialog.dismiss(); - } - }); - String message = String.format(getString(R.string.common_exit), getString(R.string.app_name)); - builder.setNegativeButton(message, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - finish(); - } - }); - //builder.setNegativeButton(android.R.string.cancel, this); - dialog = builder.create(); - break; - } - case DIALOG_ABOUT_APP: { - builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.about_title)); - PackageInfo pkg; - try { - pkg = getPackageManager().getPackageInfo(getPackageName(), 0); - builder.setMessage(String.format(getString(R.string.about_message), getString(R.string.app_name), pkg.versionName)); - builder.setIcon(android.R.drawable.ic_menu_info_details); - dialog = builder.create(); - } catch (NameNotFoundException e) { - builder = null; - dialog = null; - Log.e(TAG, "Error while showing about dialog", e); - } - break; - } - case DIALOG_CREATE_DIR: { - builder = new Builder(this); - final EditText dirNameInput = new EditText(getBaseContext()); - builder.setView(dirNameInput); - builder.setTitle(R.string.uploader_info_dirname); - int typed_color = getResources().getColor(R.color.setup_text_typed); - dirNameInput.setTextColor(typed_color); - builder.setPositiveButton(android.R.string.ok, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - String directoryName = dirNameInput.getText().toString(); - if (directoryName.trim().length() == 0) { - dialog.cancel(); - return; - } - - // Figure out the path where the dir needs to be created - String path; - if (mCurrentDir == null) { - // this is just a patch; we should ensure that - // mCurrentDir never is null - if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) { - OCFile file = new OCFile(OCFile.PATH_SEPARATOR); - mStorageManager.saveFile(file); - } - mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR); - } - path = FileDisplayActivity.this.mCurrentDir.getRemotePath(); - - // Create directory - path += directoryName + OCFile.PATH_SEPARATOR; - Thread thread = new Thread(new DirectoryCreator(path, AccountUtils - .getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler())); - thread.start(); - - dialog.dismiss(); - - showDialog(DIALOG_SHORT_WAIT); - } - }); - builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - dialog = builder.create(); - break; - } - case DIALOG_SHORT_WAIT: { - ProgressDialog working_dialog = new ProgressDialog(this); - working_dialog.setMessage(getResources().getString(R.string.wait_a_moment)); - working_dialog.setIndeterminate(true); - working_dialog.setCancelable(false); - dialog = working_dialog; - break; - } - case DIALOG_CHOOSE_UPLOAD_SOURCE: { - final String[] items = { getString(R.string.actionbar_upload_files), - getString(R.string.actionbar_upload_from_apps), getString(R.string.actionbar_failed_instant_upload) }; - builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.actionbar_upload); - builder.setItems(items, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - if (item == 0) { - // if (!mDualPane) { - Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class); - action.putExtra(UploadFilesActivity.EXTRA_ACCOUNT, - AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this)); - startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES); - // } else { - // TODO create and handle new fragment - // LocalFileListFragment - // } - } else if (item == 1) { - Intent action = new Intent(Intent.ACTION_GET_CONTENT); - action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE); - startActivityForResult(Intent.createChooser(action, getString(R.string.upload_chooser_title)), - ACTION_SELECT_CONTENT_FROM_APPS); - } else if (item == 2) { - Account account = AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this); - Intent action = new Intent(FileDisplayActivity.this, InstantUploadActivity.class); - action.putExtra(FileUploader.KEY_ACCOUNT, account); - startActivity(action); - } - } - }); - dialog = builder.create(); - break; - } - case DIALOG_SSL_VALIDATOR: { - dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this); - break; - } - case DIALOG_CERT_NOT_SAVED: { - builder = new AlertDialog.Builder(this); - builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved)); - builder.setCancelable(false); - builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - }; - }); - dialog = builder.create(); - break; - } - default: - dialog = null; - } - - return dialog; - } - - - /** - * Translates a content URI of an image to a physical path - * on the disk - * @param uri The URI to resolve - * @return The path to the image or null if it could not be found - */ - public String getPath(Uri uri) { - String[] projection = { MediaStore.Images.Media.DATA }; - Cursor cursor = managedQuery(uri, projection, null, null, null); - if (cursor != null) { - int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - cursor.moveToFirst(); - return cursor.getString(column_index); - } - return null; - } - - /** - * Pushes a directory to the drop down list - * @param directory to push - * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false. - */ - public void pushDirname(OCFile directory) { - if(!directory.isDirectory()){ - throw new IllegalArgumentException("Only directories may be pushed!"); - } - mDirectories.insert(directory.getFileName(), 0); - mCurrentDir = directory; - } - - /** - * Pops a directory name from the drop down list - * @return True, unless the stack is empty - */ - public boolean popDirname() { - mDirectories.remove(mDirectories.getItem(0)); - return !mDirectories.isEmpty(); - } - - private class DirectoryCreator implements Runnable { - private String mTargetPath; - private Account mAccount; - private Handler mHandler; - - public DirectoryCreator(String targetPath, Account account, Handler handler) { - mTargetPath = targetPath; - mAccount = account; - mHandler = handler; - } - - @Override - public void run() { - WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext()); - boolean created = wdc.createDirectory(mTargetPath); - if (created) { - mHandler.post(new Runnable() { - @Override - public void run() { - dismissDialog(DIALOG_SHORT_WAIT); - - // Save new directory in local database - OCFile newDir = new OCFile(mTargetPath); - newDir.setMimetype("DIR"); - newDir.setParentId(mCurrentDir.getFileId()); - mStorageManager.saveFile(newDir); - - // Display the new folder right away - mFileList.listDirectory(); - } - }); - - } else { - mHandler.post(new Runnable() { - @Override - public void run() { - dismissDialog(DIALOG_SHORT_WAIT); - try { - Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, - Toast.LENGTH_LONG); - msg.show(); - - } catch (NotFoundException e) { - Log.e(TAG, "Error while trying to show fail message ", e); - } - } - }); - } - } - - } - - // Custom array adapter to override text colors - private class CustomArrayAdapter extends ArrayAdapter { - - public CustomArrayAdapter(FileDisplayActivity ctx, int view) { - super(ctx, view); - } - - public View getView(int position, View convertView, ViewGroup parent) { - View v = super.getView(position, convertView, parent); - - ((TextView) v).setTextColor(getResources().getColorStateList(android.R.color.white)); - return v; - } - - public View getDropDownView(int position, View convertView, ViewGroup parent) { - View v = super.getDropDownView(position, convertView, parent); - - ((TextView) v).setTextColor(getResources().getColorStateList(android.R.color.white)); - - return v; - } - - } - - private class SyncBroadcastReceiver extends BroadcastReceiver { - - /** - * {@link BroadcastReceiver} to enable syncing feedback in UI - */ - @Override - public void onReceive(Context context, Intent intent) { - boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false); - String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME); - - Log.d("FileDisplay", "sync of account " + accountName + " is in_progress: " + inProgress); - - if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) { - - String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); - - boolean fillBlankRoot = false; - if (mCurrentDir == null) { - mCurrentDir = mStorageManager.getFileByPath("/"); - fillBlankRoot = (mCurrentDir != null); - } - - if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath() - .equals(synchFolderRemotePath))) || fillBlankRoot) { - if (!fillBlankRoot) - mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath); - OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager() - .findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(mCurrentDir); - } - } - - setSupportProgressBarIndeterminateVisibility(inProgress); - removeStickyBroadcast(intent); - - } - - RemoteOperationResult synchResult = (RemoteOperationResult) intent - .getSerializableExtra(FileSyncService.SYNC_RESULT); - if (synchResult != null) { - if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) { - mLastSslUntrustedServerResult = synchResult; - showDialog(DIALOG_SSL_VALIDATOR); - } - } - } - } - - - private class UploadFinishReceiver extends BroadcastReceiver { - /** - * Once the file upload has finished -> update view - * @author David A. Velasco - * {@link BroadcastReceiver} to enable upload feedback in UI - */ - @Override - public void onReceive(Context context, Intent intent) { - String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); - String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME); - boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name); - boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) - && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath())); - if (sameAccount && isDescendant) { - OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager() - .findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(); - } - } - } - - } - - - /** - * Once the file download has finished -> update view - */ - private class DownloadFinishReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH); - String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME); - boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name); - boolean isDescendant = (mCurrentDir != null) && (downloadedRemotePath != null) - && (downloadedRemotePath.startsWith(mCurrentDir.getRemotePath())); - if (sameAccount && isDescendant) { - OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager() - .findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(); - } - } - } - } - - - - - /** - * {@inheritDoc} - */ - @Override - public DataStorageManager getStorageManager() { - return mStorageManager; - } - - - /** - * {@inheritDoc} - */ - @Override - public void onDirectoryClick(OCFile directory) { - pushDirname(directory); - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - - if (mDualPane) { - // Resets the FileDetailsFragment on Tablets so that it always displays - FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG); - if (fileDetails != null && !fileDetails.isEmpty()) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.remove(fileDetails); - transaction.add(R.id.file_details_container, new FileDetailFragment(null, null), - FileDetailFragment.FTAG); - transaction.commit(); - } - } - } - - - /** - * {@inheritDoc} - */ - @Override - public void onFileClick(OCFile file) { - - // If we are on a large device -> update fragment - if (mDualPane) { - // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous' - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction - .replace(R.id.file_details_container, - new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), - FileDetailFragment.FTAG); - transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - transaction.commit(); - - } else { // small or medium screen device -> new Activity - Intent showDetailsIntent = new Intent(this, FileDetailActivity.class); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file); - showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); - startActivity(showDetailsIntent); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public OCFile getInitialDirectory() { - return mCurrentDir; - } - - - /** - * {@inheritDoc} - */ - @Override - public void onFileStateChanged() { - OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById( - R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(); - } - } - - - /** - * {@inheritDoc} - */ - @Override - public FileDownloaderBinder getFileDownloaderBinder() { - return mDownloaderBinder; - } - - - /** - * {@inheritDoc} - */ - @Override - public FileUploaderBinder getFileUploaderBinder() { - return mUploaderBinder; - } - - - /** Defines callbacks for service binding, passed to bindService() */ - private class ListServiceConnection implements ServiceConnection { - - @Override - public void onServiceConnected(ComponentName component, IBinder service) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { - Log.d(TAG, "Download service connected"); - mDownloaderBinder = (FileDownloaderBinder) service; - } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { - Log.d(TAG, "Upload service connected"); - mUploaderBinder = (FileUploaderBinder) service; - } else { - return; - } - // a new chance to get the mDownloadBinder through getFileDownloadBinder() - THIS IS A MESS - if (mFileList != null) - mFileList.listDirectory(); - if (mDualPane) { - FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag( - FileDetailFragment.FTAG); - if (fragment != null) - fragment.updateFileDetails(false); - } - } - - @Override - public void onServiceDisconnected(ComponentName component) { - if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) { - Log.d(TAG, "Download service disconnected"); - mDownloaderBinder = null; - } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { - Log.d(TAG, "Upload service disconnected"); - mUploaderBinder = null; - } - } - }; - - - - /** - * Launch an intent to request the PIN code to the user before letting him use the app - */ - private void requestPinCode() { - boolean pinStart = false; - SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - pinStart = appPrefs.getBoolean("set_pincode", false); - if (pinStart) { - Intent i = new Intent(getApplicationContext(), PinCodeActivity.class); - i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity"); - startActivity(i); - } - } - - - @Override - public void onSavedCertificate() { - startSynchronization(); - } - - @Override - public void onFailedSavingCertificate() { - showDialog(DIALOG_CERT_NOT_SAVED); - } - - - /** - * Updates the view associated to the activity after the finish of some operation over files - * in the current account. - * - * @param operation Removal operation performed. - * @param result Result of the removal. - */ - @Override - public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { - if (operation instanceof RemoveFileOperation) { - onRemoveFileOperationFinish((RemoveFileOperation) operation, result); - - } else if (operation instanceof RenameFileOperation) { - onRenameFileOperationFinish((RenameFileOperation) operation, result); - - } else if (operation instanceof SynchronizeFileOperation) { - onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result); - } - } - - - /** - * Updates the view associated to the activity after the finish of an operation trying to remove a - * file. - * - * @param operation Removal operation performed. - * @param result Result of the removal. - */ - private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) { - dismissDialog(DIALOG_SHORT_WAIT); - if (result.isSuccess()) { - Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG); - msg.show(); - OCFile removedFile = operation.getFile(); - if (mDualPane) { - FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag( - FileDetailFragment.FTAG); - if (details != null && removedFile.equals(details.getDisplayedFile())) { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty - // FileDetailFragment - transaction.commit(); - } - } - if (mStorageManager.getFileById(removedFile.getParentId()).equals(mCurrentDir)) { - mFileList.listDirectory(); - } - - } else { - Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); - msg.show(); - if (result.isSslRecoverableException()) { - mLastSslUntrustedServerResult = result; - showDialog(DIALOG_SSL_VALIDATOR); - } - } - } - - /** - * Updates the view associated to the activity after the finish of an operation trying to rename a - * file. - * - * @param operation Renaming operation performed. - * @param result Result of the renaming. - */ - private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) { - dismissDialog(DIALOG_SHORT_WAIT); - OCFile renamedFile = operation.getFile(); - if (result.isSuccess()) { - if (mDualPane) { - FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag( - FileDetailFragment.FTAG); - if (details != null && renamedFile.equals(details.getDisplayedFile())) { - details.updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this)); - } - } - if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) { - mFileList.listDirectory(); - } - - } else { - if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) { - Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG); - msg.show(); - // TODO throw again the new rename dialog - } else { - Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG); - msg.show(); - if (result.isSslRecoverableException()) { - mLastSslUntrustedServerResult = result; - showDialog(DIALOG_SSL_VALIDATOR); - } - } - } - } - - private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) { - dismissDialog(DIALOG_SHORT_WAIT); - OCFile syncedFile = operation.getLocalFile(); - if (!result.isSuccess()) { - if (result.getCode() == ResultCode.SYNC_CONFLICT) { - Intent i = new Intent(this, ConflictsResolveActivity.class); - i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile); - i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this)); - startActivity(i); - - } else { - Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); - msg.show(); - } - - } else { - if (operation.transferWasRequested()) { - mFileList.listDirectory(); - onTransferStateChanged(syncedFile, true, true); - - } else { - Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); - msg.show(); - } - } - } - - - /** - * {@inheritDoc} - */ - @Override - public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) { - /*OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList); - if (fileListFragment != null) { - fileListFragment.listDirectory(); - }*/ - if (mDualPane) { - FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag( - FileDetailFragment.FTAG); - if (details != null && file.equals(details.getDisplayedFile())) { - if (downloading || uploading) { - details.updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this)); - } else { - details.updateFileDetails(downloading || uploading); - } - } - } - } - - - - - -}