From: masensio Date: Wed, 2 Sep 2015 11:21:17 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/master' into text_file_preview_pr_707_with_develop X-Git-Tag: oc-android-1.8~17^2~5 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/a0707428ff3f82f28261afc1cdc3061b534f47e2?hp=f626b136340578c29a52abbe247b5d10cf90b50f Merge remote-tracking branch 'origin/master' into text_file_preview_pr_707_with_develop Conflicts: res/layout/file_preview.xml src/com/owncloud/android/ui/activity/FileDisplayActivity.java --- diff --git a/res/layout/file_preview.xml b/res/layout/file_preview.xml index 2068224d..f7a697a0 100644 --- a/res/layout/file_preview.xml +++ b/res/layout/file_preview.xml @@ -25,9 +25,9 @@ android:layout_height="match_parent" android:background="@color/background_color" android:gravity="center" - tools:context=".ui.fragment.FilePreviewFragment" > + tools:context=".ui.fragment.FilePreviewFragment"> - + + + + \ No newline at end of file diff --git a/src/com/owncloud/android/datamodel/OCFile.java b/src/com/owncloud/android/datamodel/OCFile.java index 2aa5dbc0..4baf1ea5 100644 --- a/src/com/owncloud/android/datamodel/OCFile.java +++ b/src/com/owncloud/android/datamodel/OCFile.java @@ -22,9 +22,9 @@ package com.owncloud.android.datamodel; import android.os.Parcel; import android.os.Parcelable; +import android.webkit.MimeTypeMap; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.utils.FileStorageUtils; import java.io.File; @@ -289,11 +289,13 @@ public class OCFile implements Parcelable, Comparable { /** * Sets the name of the file *

- * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory + * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root + * directory */ public void setFileName(String name) { Log_OC.d(TAG, "OCFile name changin from " + mRemotePath); - if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !mRemotePath.equals(ROOT_PATH)) { + if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && + !mRemotePath.equals(ROOT_PATH)) { String parent = (new File(getRemotePath())).getParent(); parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR; mRemotePath = parent + name; @@ -454,7 +456,7 @@ public class OCFile implements Parcelable, Comparable { @Override public int describeContents() { - return ((Object) this).hashCode(); + return super.hashCode(); } @Override @@ -483,8 +485,11 @@ public class OCFile implements Parcelable, Comparable { @Override public String toString() { - String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, parentId=%s, favorite=%s etag=%s]"; - asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mFavorite), mEtag); + String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " + + "parentId=%s, favorite=%s etag=%s]"; + asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(), + mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mFavorite), + mEtag); return asString; } @@ -540,7 +545,26 @@ public class OCFile implements Parcelable, Comparable { */ public boolean isImage() { return ((mMimeType != null && mMimeType.startsWith("image/")) || - FileStorageUtils.getMimeTypeFromName(mRemotePath).startsWith("image/")); + getMimeTypeFromName().startsWith("image/")); + } + + /** + * @return 'True' if the file is simple text (e.g. not application-dependent, like .doc or .docx) + */ + public boolean isText() { + return ((mMimeType != null && mMimeType.startsWith("text/")) || + getMimeTypeFromName().startsWith("text/")); + } + + public String getMimeTypeFromName() { + String extension = ""; + int pos = mRemotePath.lastIndexOf('.'); + if (pos >= 0) { + extension = mRemotePath.substring(pos + 1); + } + String result = MimeTypeMap.getSingleton(). + getMimeTypeFromExtension(extension.toLowerCase()); + return (result != null) ? result : ""; } /** diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index 9c1d0661..ede00340 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -98,6 +98,7 @@ 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.ui.preview.PreviewTextFragment; import com.owncloud.android.ui.preview.PreviewVideoActivity; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ErrorMessageAdapter; @@ -106,7 +107,6 @@ import com.owncloud.android.utils.UriUtils; import java.io.File; - /** * Displays, what files the user has available in his ownCloud. */ @@ -115,6 +115,8 @@ public class FileDisplayActivity extends HookActivity implements FileFragment.ContainerActivity, OnSslUntrustedCertListener, OnEnforceableRefreshListener { + + private SyncBroadcastReceiver mSyncBroadcastReceiver; private UploadFinishReceiver mUploadFinishReceiver; private DownloadFinishReceiver mDownloadFinishReceiver; @@ -141,7 +143,7 @@ public class FileDisplayActivity extends HookActivity private static final String TAG_SECOND_FRAGMENT = "SECOND_FRAGMENT"; private OCFile mWaitingToPreview; - + private boolean mSyncInProgress = false; private static String DIALOG_UNTRUSTED_CERT = "DIALOG_UNTRUSTED_CERT"; @@ -164,7 +166,7 @@ public class FileDisplayActivity extends HookActivity Intent initObserversIntent = FileObserverService.makeInitIntent(this); startService(initObserversIntent); } - + /// Load of saved instance state if(savedInstanceState != null) { mWaitingToPreview = (OCFile) savedInstanceState.getParcelable( @@ -172,12 +174,11 @@ public class FileDisplayActivity extends HookActivity mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS); mWaitingToSend = (OCFile) savedInstanceState.getParcelable( FileDisplayActivity.KEY_WAITING_TO_SEND); - } else { mWaitingToPreview = null; mSyncInProgress = false; mWaitingToSend = null; - } + } /// USER INTERFACE @@ -210,7 +211,7 @@ public class FileDisplayActivity extends HookActivity mProgressBar.setIndeterminate(mSyncInProgress); // always AFTER setContentView(...) ; to work around bug in its implementation - + setBackgroundText(); Log_OC.v(TAG, "onCreate() end"); @@ -231,8 +232,8 @@ public class FileDisplayActivity extends HookActivity } /** - * Called when the ownCloud {@link Account} associated to the Activity was just updated. - */ + * Called when the ownCloud {@link Account} associated to the Activity was just updated. + */ @Override protected void onAccountSet(boolean stateWasRecovered) { super.onAccountSet(stateWasRecovered); @@ -276,7 +277,7 @@ public class FileDisplayActivity extends HookActivity if (file.isFolder()) { startSyncFolderOperation(file, false); } - + } else { updateFragmentsVisibility(!file.isFolder()); updateActionBarTitleAndHomeButton(file.isFolder() ? null : file); @@ -284,36 +285,38 @@ public class FileDisplayActivity extends HookActivity } } - private void createMinFragments() { OCFileListFragment listOfFiles = new OCFileListFragment(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.left_fragment_container, listOfFiles, TAG_LIST_OF_FILES); transaction.commit(); } - + private void initFragmentsWithFile() { if (getAccount() != null && getFile() != null) { /// First fragment - OCFileListFragment listOfFiles = getListOfFilesFragment(); + OCFileListFragment listOfFiles = getListOfFilesFragment(); if (listOfFiles != null) { listOfFiles.listDirectory(getCurrentDir()); // TODO Enable when "On Device" is recovered // listOfFiles.listDirectory(getCurrentDir(), MainApp.getOnlyOnDevice()); + } else { Log_OC.e(TAG, "Still have a chance to lose the initializacion of list fragment >("); } - + /// Second fragment - OCFile file = getFile(); + OCFile file = getFile(); Fragment secondFragment = chooseInitialSecondFragment(file); if (secondFragment != null) { setSecondFragment(secondFragment); updateFragmentsVisibility(true); updateActionBarTitleAndHomeButton(file); - + } else { cleanSecondFragment(); + if (file.isDown() && PreviewTextFragment.canBePreviewed(file)) + startTextPreview(file); } } else { @@ -330,7 +333,7 @@ public class FileDisplayActivity extends HookActivity private Fragment chooseInitialSecondFragment(OCFile file) { Fragment secondFragment = null; if (file != null && !file.isFolder()) { - if (file.isDown() && PreviewMediaFragment.canBePreviewed(file) + if (file.isDown() && PreviewMediaFragment.canBePreviewed(file) && file.getLastSyncDateForProperties() > 0 // temporal fix ) { int startPlaybackPosition = @@ -340,9 +343,11 @@ public class FileDisplayActivity extends HookActivity secondFragment = new PreviewMediaFragment(file, getAccount(), startPlaybackPosition, autoplay); + } else if (file.isDown() && PreviewTextFragment.canBePreviewed(file)) { + secondFragment = null; } else { - secondFragment = FileDetailFragment.newInstance(file, getAccount()); - } + secondFragment = FileDetailFragment.newInstance(file, getAccount()); + } } return secondFragment; } @@ -351,10 +356,10 @@ public class FileDisplayActivity extends HookActivity /** * Replaces the second fragment managed by the activity with the received as * a parameter. - * - * Assumes never will be more than two fragments managed at the same time. - * - * @param fragment New second Fragment to set. + *

+ * Assumes never will be more than two fragments managed at the same time. + * + * @param fragment New second Fragment to set. */ private void setSecondFragment(Fragment fragment) { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); @@ -395,7 +400,7 @@ public class FileDisplayActivity extends HookActivity Fragment listOfFiles = getSupportFragmentManager().findFragmentByTag( FileDisplayActivity.TAG_LIST_OF_FILES); if (listOfFiles != null) { - return (OCFileListFragment)listOfFiles; + return (OCFileListFragment) listOfFiles; } Log_OC.wtf(TAG, "Access to unexisting list of files fragment!!"); return null; @@ -405,7 +410,7 @@ public class FileDisplayActivity extends HookActivity Fragment second = getSupportFragmentManager().findFragmentByTag( FileDisplayActivity.TAG_SECOND_FRAGMENT); if (second != null) { - return (FileFragment)second; + return (FileFragment) second; } return null; } @@ -459,6 +464,9 @@ public class FileDisplayActivity extends HookActivity if (PreviewMediaFragment.canBePreviewed(mWaitingToPreview)) { startMediaPreview(mWaitingToPreview, 0, true); detailsFragmentChanged = true; + } else if (PreviewTextFragment.canBePreviewed(mWaitingToPreview)) { + startTextPreview(mWaitingToPreview); + detailsFragmentChanged = true; } else { getFileOperationsHelper().openFile(mWaitingToPreview); } @@ -501,6 +509,7 @@ public class FileDisplayActivity extends HookActivity dialog.show(getSupportFragmentManager(), DIALOG_CREATE_FOLDER); break; } + case R.id.action_sync_account: { startSynchronization(); break; @@ -509,7 +518,6 @@ public class FileDisplayActivity extends HookActivity UploadSourceDialogFragment dialog = UploadSourceDialogFragment.newInstance(getAccount()); dialog.show(getSupportFragmentManager(), DIALOG_UPLOAD_SOURCE); - break; } case android.R.id.home: { @@ -616,18 +624,18 @@ public class FileDisplayActivity extends HookActivity resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) { requestMultipleUpload(data, resultCode); - } else if (requestCode == ACTION_MOVE_FILES && resultCode == RESULT_OK){ + } else if (requestCode == ACTION_MOVE_FILES && resultCode == RESULT_OK) { final Intent fData = data; - final int fResultCode = resultCode; + final int fResultCode = resultCode; getHandler().postDelayed( - new Runnable() { - @Override - public void run() { - requestMoveOperation(fData, fResultCode); - } - }, - DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS + new Runnable() { + @Override + public void run() { + requestMoveOperation(fData, fResultCode); + } + }, + DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS ); } else { @@ -735,9 +743,9 @@ public class FileDisplayActivity extends HookActivity /** * Request the operation for moving the file/folder from one path to another - * - * @param data Intent received - * @param resultCode Result code received + * + * @param data Intent received + * @param resultCode Result code received */ private void requestMoveOperation(Intent data, int resultCode) { OCFile folderToMoveAt = (OCFile) data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER); @@ -782,18 +790,15 @@ public class FileDisplayActivity extends HookActivity Log_OC.v(TAG, "onSaveInstanceState() end"); } - @Override protected void onResume() { Log_OC.v(TAG, "onResume() start"); super.onResume(); - // refresh Navigation Drawer account list mNavigationDrawerAdapter.updateAccountList(); - // refresh list of files refreshListOfFilesFragment(); @@ -819,8 +824,8 @@ public class FileDisplayActivity extends HookActivity downloadIntentFilter.addAction(FileDownloader.getDownloadFinishMessage()); mDownloadFinishReceiver = new DownloadFinishReceiver(); registerReceiver(mDownloadFinishReceiver, downloadIntentFilter); - Log_OC.v(TAG, "onResume() end"); + } @@ -840,7 +845,7 @@ public class FileDisplayActivity extends HookActivity unregisterReceiver(mDownloadFinishReceiver); mDownloadFinishReceiver = null; } - + super.onPause(); Log_OC.v(TAG, "onPause() end"); } @@ -864,12 +869,12 @@ public class FileDisplayActivity extends HookActivity FileSyncAdapter.EXTRA_RESULT); boolean sameAccount = (getAccount() != null && accountName.equals(getAccount().name) && getStorageManager() != null); - + if (sameAccount) { - + if (FileSyncAdapter.EVENT_FULL_SYNC_START.equals(event)) { mSyncInProgress = true; - + } else { OCFile currentFile = (getFile() == null) ? null : getStorageManager().getFileByPath(getFile().getRemotePath()); @@ -885,8 +890,9 @@ public class FileDisplayActivity extends HookActivity synchFolderRemotePath), Toast.LENGTH_LONG) .show(); + browseToRoot(); - + } else { if (currentFile == null && !getFile().isFolder()) { // currently selected file was removed in the server, and now we @@ -907,19 +913,18 @@ public class FileDisplayActivity extends HookActivity } setFile(currentFile); } - + mSyncInProgress = (!FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && !RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED .equals(event)); if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED. - equals(event) && - /// TODO refactor and make common - synchResult != null && !synchResult.isSuccess() && - (synchResult.getCode() == ResultCode.UNAUTHORIZED || - synchResult.isIdPRedirection() || - (synchResult.isException() && synchResult.getException() - instanceof AuthenticatorException))) { + equals(event) &&/// TODO refactor and make common + synchResult != null && !synchResult.isSuccess() && + (synchResult.getCode() == ResultCode.UNAUTHORIZED || + synchResult.isIdPRedirection() || + (synchResult.isException() && synchResult.getException() + instanceof AuthenticatorException))) { try { @@ -928,7 +933,6 @@ public class FileDisplayActivity extends HookActivity new OwnCloudAccount(getAccount(), context); client = (OwnCloudClientManagerFactory.getDefaultSingleton(). removeClientFor(ocAccount)); - if (client != null) { OwnCloudCredentials cred = client.getCredentials(); if (cred != null) { @@ -959,9 +963,9 @@ public class FileDisplayActivity extends HookActivity /*|| mRefreshSharesInProgress*/ //); setBackgroundText(); - + } - + if (synchResult != null) { if (synchResult.getCode().equals( RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) { @@ -975,7 +979,7 @@ public class FileDisplayActivity extends HookActivity } } } - + /** * Show a text message on screen view for notifying user if content is * loading or folder is empty @@ -1000,7 +1004,8 @@ public class FileDisplayActivity extends HookActivity private class UploadFinishReceiver extends BroadcastReceiver { /** * Once the file upload has finished -> update view - * @author David A. Velasco + * + * @author David A. Velasco * {@link BroadcastReceiver} to enable upload feedback in UI */ @Override @@ -1010,23 +1015,22 @@ public class FileDisplayActivity extends HookActivity String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME); boolean sameAccount = getAccount() != null && accountName.equals(getAccount().name); OCFile currentDir = getCurrentDir(); - boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) && + boolean isDescendant = (currentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(currentDir.getRemotePath())); - + if (sameAccount && isDescendant) { refreshListOfFilesFragment(); } - boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false); boolean renamedInUpload = getFile().getRemotePath(). equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH)); - boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) || + boolean sameFile = getFile().getRemotePath().equals(uploadedRemotePath) || renamedInUpload; FileFragment details = getSecondFragment(); - boolean detailFragmentIsShown = (details != null && + boolean detailFragmentIsShown = (details != null && details instanceof FileDetailFragment); - + if (sameAccount && sameFile && detailFragmentIsShown) { if (uploadWasFine) { setFile(getStorageManager().getFileByPath(uploadedRemotePath)); @@ -1034,23 +1038,28 @@ public class FileDisplayActivity extends HookActivity if (renamedInUpload) { String newName = (new File(uploadedRemotePath)).getName(); Toast msg = Toast.makeText( - context, + context, String.format( - getString(R.string.filedetails_renamed_in_upload_msg), - newName), + getString(R.string.filedetails_renamed_in_upload_msg), + newName), Toast.LENGTH_LONG); msg.show(); } if (uploadWasFine || getFile().fileExists()) { - ((FileDetailFragment)details).updateFileDetails(false, true); + ((FileDetailFragment) details).updateFileDetails(false, true); } else { cleanSecondFragment(); } - - // Force the preview if the file is an image - if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) { - startImagePreview(getFile()); - } // TODO what about other kind of previews? + + // Force the preview if the file is an image or text file + if (uploadWasFine) { + OCFile ocFile = getFile(); + if (PreviewImageFragment.canBePreviewed(ocFile)) + startImagePreview(getFile()); + else if (PreviewTextFragment.canBePreviewed(ocFile)) + startTextPreview(ocFile); + // TODO what about other kind of previews? + } } mProgressBar.setIndeterminate(false); @@ -1059,15 +1068,15 @@ public class FileDisplayActivity extends HookActivity removeStickyBroadcast(intent); } } - + } - + } /** * Class waiting for broadcast events from the {@link FileDownloader} service. - * + * * Updates the UI when a download is started or finished, provided that it is relevant for the * current folder. */ @@ -1095,15 +1104,15 @@ public class FileDisplayActivity extends HookActivity intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false) ); } - + if (mWaitingToSend != null) { mWaitingToSend = getStorageManager().getFileByPath(mWaitingToSend.getRemotePath()); - if (mWaitingToSend.isDown()) { + if (mWaitingToSend.isDown()) { sendDownloadedFile(); } } - + } finally { if (intent != null) { removeStickyBroadcast(intent); @@ -1134,10 +1143,10 @@ public class FileDisplayActivity extends HookActivity accountName.equals(getAccount().name)); } } - - + + public void browseToRoot() { - OCFileListFragment listOfFiles = getListOfFilesFragment(); + OCFileListFragment listOfFiles = getListOfFilesFragment(); if (listOfFiles != null) { // should never be null, indeed OCFile root = getStorageManager().getFileByPath(OCFile.ROOT_PATH); listOfFiles.listDirectory(root); @@ -1147,13 +1156,12 @@ public class FileDisplayActivity extends HookActivity startSyncFolderOperation(root, false); } cleanSecondFragment(); - } /** * {@inheritDoc} - * + *

* Updates action bar and second fragment, if in dual pane mode. */ @Override @@ -1165,10 +1173,10 @@ public class FileDisplayActivity extends HookActivity } /** - * Shows the information of the {@link OCFile} received as a + * Shows the information of the {@link OCFile} received as a * parameter in the second fragment. - * - * @param file {@link OCFile} whose details will be shown + * + * @param file {@link OCFile} whose details will be shown */ @Override public void showDetails(OCFile file) { @@ -1196,7 +1204,9 @@ public class FileDisplayActivity extends HookActivity return new ListServiceConnection(); } - /** Defines callbacks for service binding, passed to bindService() */ + /** + * Defines callbacks for service binding, passed to bindService() + */ private class ListServiceConnection implements ServiceConnection { @Override @@ -1213,7 +1223,7 @@ public class FileDisplayActivity extends HookActivity if (!mWaitingToPreview.isDown()) { requestForDownload(); } - } + } } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) { @@ -1224,7 +1234,7 @@ public class FileDisplayActivity extends HookActivity } // a new chance to get the mDownloadBinder through // getFileDownloadBinder() - THIS IS A MESS - OCFileListFragment listOfFiles = getListOfFilesFragment(); + OCFileListFragment listOfFiles = getListOfFilesFragment(); if (listOfFiles != null) { listOfFiles.listDirectory(); // TODO Enable when "On Device" is recovered ? @@ -1232,7 +1242,7 @@ public class FileDisplayActivity extends HookActivity } FileFragment secondFragment = getSecondFragment(); if (secondFragment != null && secondFragment instanceof FileDetailFragment) { - FileDetailFragment detailFragment = (FileDetailFragment)secondFragment; + FileDetailFragment detailFragment = (FileDetailFragment) secondFragment; detailFragment.listenForTransferProgress(); detailFragment.updateFileDetails(false, false); } @@ -1250,7 +1260,7 @@ public class FileDisplayActivity extends HookActivity mUploaderBinder = null; } } - }; + } @Override public void onSavedCertificate() { @@ -1274,38 +1284,37 @@ public class FileDisplayActivity extends HookActivity /** * 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. + * + * @param operation Removal operation performed. + * @param result Result of the removal. */ @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { super.onRemoteOperationFinish(operation, result); - + if (operation instanceof RemoveFileOperation) { onRemoveFileOperationFinish((RemoveFileOperation) operation, result); } else if (operation instanceof RenameFileOperation) { - onRenameFileOperationFinish((RenameFileOperation)operation, result); + onRenameFileOperationFinish((RenameFileOperation) operation, result); } else if (operation instanceof SynchronizeFileOperation) { - onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result); + onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result); } else if (operation instanceof CreateFolderOperation) { - onCreateFolderOperationFinish((CreateFolderOperation)operation, result); - + onCreateFolderOperationFinish((CreateFolderOperation) operation, result); + } else if (operation instanceof CreateShareOperation) { onCreateShareOperationFinish((CreateShareOperation) operation, result); - + } else if (operation instanceof UnshareLinkOperation) { - onUnshareLinkOperationFinish((UnshareLinkOperation)operation, result); - + onUnshareLinkOperationFinish((UnshareLinkOperation) operation, result); + } else if (operation instanceof MoveFileOperation) { - onMoveFileOperationFinish((MoveFileOperation)operation, result); + onMoveFileOperationFinish((MoveFileOperation) operation, result); } - - } + } private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) { @@ -1315,36 +1324,37 @@ public class FileDisplayActivity extends HookActivity } } - private void onUnshareLinkOperationFinish(UnshareLinkOperation operation, RemoteOperationResult result) { if (result.isSuccess()) { refreshShowDetails(); refreshListOfFilesFragment(); - + } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { cleanSecondFragment(); refreshListOfFilesFragment(); } } - + private void refreshShowDetails() { FileFragment details = getSecondFragment(); if (details != null) { OCFile file = details.getFile(); if (file != null) { - file = getStorageManager().getFileByPath(file.getRemotePath()); + file = getStorageManager().getFileByPath(file.getRemotePath()); if (details instanceof PreviewMediaFragment) { // Refresh OCFile of the fragment ((PreviewMediaFragment) details).updateFile(file); - } else { + } else if (details instanceof PreviewTextFragment) { + // Refresh OCFile of the fragment + ((PreviewTextFragment) details).updateFile(file); + } else showDetails(file); - } } invalidateOptionsMenu(); - } + } } - + /** * Updates the view associated to the activity after the finish of an operation trying to * remove a file. @@ -1355,23 +1365,22 @@ public class FileDisplayActivity extends HookActivity private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) { dismissLoadingDialog(); - Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), - Toast.LENGTH_LONG); + Toast.LENGTH_LONG); msg.show(); - + if (result.isSuccess()) { OCFile removedFile = operation.getFile(); FileFragment second = getSecondFragment(); if (second != null && removedFile.equals(second.getFile())) { if (second instanceof PreviewMediaFragment) { - ((PreviewMediaFragment)second).stopPreview(true); + ((PreviewMediaFragment) second).stopPreview(true); } setFile(getStorageManager().getFileById(removedFile.getParentId())); cleanSecondFragment(); } - if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())) { + if (getStorageManager().getFileById(removedFile.getParentId()).equals(getCurrentDir())){ refreshListOfFilesFragment(); } invalidateOptionsMenu(); @@ -1382,14 +1391,14 @@ public class FileDisplayActivity extends HookActivity } } } - - + + /** - * Updates the view associated to the activity after the finish of an operation trying to move a + * Updates the view associated to the activity after the finish of an operation trying to move a * file. - * - * @param operation Move operation performed. - * @param result Result of the move operation. + * + * @param operation Move operation performed. + * @param result Result of the move operation. */ private void onMoveFileOperationFinish(MoveFileOperation operation, RemoteOperationResult result) { @@ -1399,13 +1408,13 @@ public class FileDisplayActivity extends HookActivity } else { dismissLoadingDialog(); try { - Toast msg = Toast.makeText(FileDisplayActivity.this, - ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), - Toast.LENGTH_LONG); + Toast msg = Toast.makeText(FileDisplayActivity.this, + ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); msg.show(); } catch (NotFoundException e) { - Log_OC.e(TAG, "Error while trying to show fail message " , e); + Log_OC.e(TAG, "Error while trying to show fail message ", e); } } } @@ -1434,11 +1443,19 @@ public class FileDisplayActivity extends HookActivity renamedFile.equals(details.getFile())) { ((PreviewMediaFragment) details).updateFile(renamedFile); if (PreviewMediaFragment.canBePreviewed(renamedFile)) { - int position = ((PreviewMediaFragment)details).getPosition(); + int position = ((PreviewMediaFragment) details).getPosition(); startMediaPreview(renamedFile, position, true); } else { getFileOperationsHelper().openFile(renamedFile); } + } else if (details instanceof PreviewTextFragment && + renamedFile.equals(details.getFile())) { + ((PreviewTextFragment) details).updateFile(renamedFile); + if (PreviewTextFragment.canBePreviewed(renamedFile)) { + startTextPreview(renamedFile); + } else { + getFileOperationsHelper().openFile(renamedFile); + } } } @@ -1449,9 +1466,9 @@ public class FileDisplayActivity extends HookActivity } else { Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), - Toast.LENGTH_LONG); + Toast.LENGTH_LONG); msg.show(); - + if (result.isSslRecoverableException()) { mLastSslUntrustedServerResult = result; showUntrustedCertDialog(mLastSslUntrustedServerResult); @@ -1485,18 +1502,18 @@ public class FileDisplayActivity extends HookActivity } else { dismissLoadingDialog(); try { - Toast msg = Toast.makeText(FileDisplayActivity.this, - ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), - Toast.LENGTH_LONG); + Toast msg = Toast.makeText(FileDisplayActivity.this, + ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); msg.show(); } catch (NotFoundException e) { - Log_OC.e(TAG, "Error while trying to show fail message " , e); + Log_OC.e(TAG, "Error while trying to show fail message ", e); } } } - + /** * {@inheritDoc} */ @@ -1507,16 +1524,16 @@ public class FileDisplayActivity extends HookActivity if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) { if (downloading || uploading) { - ((FileDetailFragment)details).updateFileDetails(file, getAccount()); + ((FileDetailFragment) details).updateFileDetails(file, getAccount()); } else { if (!file.fileExists()) { cleanSecondFragment(); } else { - ((FileDetailFragment)details).updateFileDetails(false, true); + ((FileDetailFragment) details).updateFileDetails(false, true); } } } - + } @@ -1545,12 +1562,12 @@ public class FileDisplayActivity extends HookActivity } return null; } - + public void startSyncFolderOperation(OCFile folder, boolean ignoreETag) { - long currentSyncTime = System.currentTimeMillis(); - + long currentSyncTime = System.currentTimeMillis(); + mSyncInProgress = true; - + // perform folder synchronization RemoteOperation synchFolderOp = new RefreshFolderOperation( folder, currentSyncTime, @@ -1562,13 +1579,14 @@ public class FileDisplayActivity extends HookActivity getApplicationContext() ); synchFolderOp.execute(getAccount(), MainApp.getAppContext(), this, null, null); + mProgressBar.setIndeterminate(true); setBackgroundText(); } /** - * Show untrusted cert dialog + * Show untrusted cert dialog */ public void showUntrustedCertDialog(RemoteOperationResult result) { // Show a dialog with the certificate info @@ -1578,7 +1596,7 @@ public class FileDisplayActivity extends HookActivity FragmentTransaction ft = fm.beginTransaction(); dialog.show(ft, DIALOG_UNTRUSTED_CERT); } - + private void requestForDownload(OCFile file) { Account account = getAccount(); if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) { @@ -1588,38 +1606,37 @@ public class FileDisplayActivity extends HookActivity startService(i); } } - - private void sendDownloadedFile(){ + + private void sendDownloadedFile() { getFileOperationsHelper().sendDownloadedFile(mWaitingToSend); mWaitingToSend = null; } - + /** * Requests the download of the received {@link OCFile} , updates the UI * to monitor the download progress and prepares the activity to send the file * when the download finishes. - * - * @param file {@link OCFile} to download and preview. + * + * @param file {@link OCFile} to download and preview. */ public void startDownloadForSending(OCFile file) { mWaitingToSend = file; requestForDownload(mWaitingToSend); - boolean hasSecondFragment = (getSecondFragment()!= null); + boolean hasSecondFragment = (getSecondFragment() != null); updateFragmentsVisibility(hasSecondFragment); } - + /** * Opens the image gallery showing the image {@link OCFile} received as parameter. - * - * @param file Image {@link OCFile} to show. + * + * @param file Image {@link OCFile} to show. */ public void startImagePreview(OCFile file) { Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class); showDetailsIntent.putExtra(EXTRA_FILE, file); showDetailsIntent.putExtra(EXTRA_ACCOUNT, getAccount()); startActivity(showDetailsIntent); - } /** @@ -1641,11 +1658,28 @@ public class FileDisplayActivity extends HookActivity } /** + * Stars the preview of a text file {@link OCFile}. + * + * @param file Text {@link OCFile} to preview. + */ + public void startTextPreview(OCFile file) { + Bundle args = new Bundle(); + args.putParcelable(EXTRA_FILE, file); + args.putParcelable(EXTRA_ACCOUNT, getAccount()); + Fragment textPreviewFragment = Fragment.instantiate(getApplicationContext(), + PreviewTextFragment.class.getName(), args); + setSecondFragment(textPreviewFragment); + updateFragmentsVisibility(true); + //updateNavigationElementsInActionBar(file); + setFile(file); + } + + /** * Requests the download of the received {@link OCFile} , updates the UI * to monitor the download progress and prepares the activity to preview * or open the file when the download finishes. - * - * @param file {@link OCFile} to download and preview. + * + * @param file {@link OCFile} to download and preview. */ public void startDownloadForPreview(OCFile file) { Fragment detailFragment = FileDetailFragment.newInstance(file, getAccount()); @@ -1660,7 +1694,7 @@ public class FileDisplayActivity extends HookActivity public void cancelTransference(OCFile file) { getFileOperationsHelper().cancelTransference(file); - if (mWaitingToPreview != null && + if (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(file.getRemotePath())) { mWaitingToPreview = null; } @@ -1693,15 +1727,15 @@ public class FileDisplayActivity extends HookActivity } } - private void sortByDate(boolean ascending){ + private void sortByDate(boolean ascending) { getListOfFilesFragment().sortByDate(ascending); } - private void sortBySize(boolean ascending){ + private void sortBySize(boolean ascending) { getListOfFilesFragment().sortBySize(ascending); } - private void sortByName(boolean ascending){ + private void sortByName(boolean ascending) { getListOfFilesFragment().sortByName(ascending); } diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index 5ec5c52c..e0004b17 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -57,6 +57,7 @@ import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.ui.preview.PreviewMediaFragment; import com.owncloud.android.utils.DialogMenuItem; import com.owncloud.android.utils.FileStorageUtils; +import com.owncloud.android.ui.preview.PreviewTextFragment; /** * A Fragment that lists all files and folders in a given path. @@ -272,7 +273,8 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActi if (PreviewImageFragment.canBePreviewed(file)) { // preview image - it handles the download, if needed ((FileDisplayActivity)mContainerActivity).startImagePreview(file); - + } else if (PreviewTextFragment.canBePreviewed(file)){ + ((FileDisplayActivity)mContainerActivity).startTextPreview(file); } else if (file.isDown()) { if (PreviewMediaFragment.canBePreviewed(file)) { // media preview diff --git a/src/com/owncloud/android/ui/preview/PreviewTextFragment.java b/src/com/owncloud/android/ui/preview/PreviewTextFragment.java new file mode 100644 index 00000000..e9479a35 --- /dev/null +++ b/src/com/owncloud/android/ui/preview/PreviewTextFragment.java @@ -0,0 +1,397 @@ +package com.owncloud.android.ui.preview; + +import android.accounts.Account; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.owncloud.android.R; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.files.FileMenuFilter; +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.ui.activity.FileDisplayActivity; +import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; +import com.owncloud.android.ui.dialog.LoadingDialog; +import com.owncloud.android.ui.dialog.RemoveFileDialogFragment; +import com.owncloud.android.ui.fragment.FileFragment; + +import java.io.BufferedWriter; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.ref.WeakReference; +import java.util.Scanner; + +public class PreviewTextFragment extends FileFragment { + private static final String EXTRA_FILE = "FILE"; + private static final String EXTRA_ACCOUNT = "ACCOUNT"; + private static final String TAG = PreviewTextFragment.class.getSimpleName(); + + private Account mAccount; + private TextView mTextPreview; + private TextLoadAsyncTask mTextLoadTask; + + /** + * Creates an empty fragment for previews. + *

+ * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically + * (for instance, when the device is turned a aside). + *

+ * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful + * construction + */ + public PreviewTextFragment() { + super(); + mAccount = null; + } + + /** + * {@inheritDoc} + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + Log_OC.e(TAG, "onCreateView"); + + + View ret = inflater.inflate(R.layout.text_file_preview, container, false); + + mTextPreview = (TextView) ret.findViewById(R.id.text_preview); + + return ret; + } + + /** + * {@inheritDoc} + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + OCFile file = getFile(); + + Bundle args = getArguments(); + + if (file == null) { + file = args.getParcelable(FileDisplayActivity.EXTRA_FILE); + } + + if (mAccount == null) { + mAccount = args.getParcelable(FileDisplayActivity.EXTRA_ACCOUNT); + } + + if (savedInstanceState == null) { + if (file == null) { + throw new IllegalStateException("Instanced with a NULL OCFile"); + } + if (mAccount == null) { + throw new IllegalStateException("Instanced with a NULL ownCloud Account"); + } + } else { + file = savedInstanceState.getParcelable(EXTRA_FILE); + mAccount = savedInstanceState.getParcelable(EXTRA_ACCOUNT); + } + setFile(file); + setHasOptionsMenu(true); + } + + /** + * {@inheritDoc} + */ + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelable(PreviewTextFragment.EXTRA_FILE, getFile()); + outState.putParcelable(PreviewTextFragment.EXTRA_ACCOUNT, mAccount); + } + + @Override + public void onStart() { + super.onStart(); + Log_OC.e(TAG, "onStart"); + + loadAndShowTextPreview(); + } + + private void loadAndShowTextPreview() { + mTextLoadTask = new TextLoadAsyncTask(new WeakReference(mTextPreview)); + mTextLoadTask.execute(getFile().getStoragePath()); + } + + + /** + * Reads the file to preview and shows its contents. Too critical to be anonymous. + */ + private class TextLoadAsyncTask extends AsyncTask { + private final String DIALOG_WAIT_TAG = "DIALOG_WAIT"; + private final WeakReference mTextViewReference; + + private TextLoadAsyncTask(WeakReference textView) { + mTextViewReference = textView; + } + + + @Override + protected void onPreExecute() { + showLoadingDialog(); + } + + @Override + protected StringWriter doInBackground(java.lang.Object... params) { + if (params.length != 1) { + throw new IllegalArgumentException("The parameter to " + TextLoadAsyncTask.class.getName() + " must be (1) the file location"); + } + final String location = (String) params[0]; + + FileInputStream inputStream = null; + Scanner sc = null; + StringWriter source = new StringWriter(); + BufferedWriter bufferedWriter = new BufferedWriter(source); + try { + inputStream = new FileInputStream(location); + sc = new Scanner(inputStream); + while (sc.hasNextLine()) { + bufferedWriter.append(sc.nextLine()); + if (sc.hasNextLine()) bufferedWriter.append("\n"); + } + bufferedWriter.close(); + IOException exc = sc.ioException(); + if (exc != null) throw exc; + } catch (IOException e) { + Log_OC.e(TAG, e.getMessage(), e); + finish(); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + Log_OC.e(TAG, e.getMessage(), e); + finish(); + } + } + if (sc != null) { + sc.close(); + } + } + return source; + } + + @Override + protected void onPostExecute(final StringWriter stringWriter) { + final TextView textView = mTextViewReference.get(); + + if (textView != null) { + textView.setText(new String(stringWriter.getBuffer())); + textView.setVisibility(View.VISIBLE); + } + + dismissLoadingDialog(); + } + + /** + * Show loading dialog + */ + public void showLoadingDialog() { + // Construct dialog + LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment)); + FragmentManager fm = getActivity().getSupportFragmentManager(); + FragmentTransaction ft = fm.beginTransaction(); + loading.show(ft, DIALOG_WAIT_TAG); + } + + /** + * Dismiss loading dialog + */ + public void dismissLoadingDialog() { + final Fragment frag = getActivity().getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG); + if (frag != null) { + LoadingDialog loading = (LoadingDialog) frag; + loading.dismiss(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.file_actions_menu, menu); + } + + /** + * {@inheritDoc} + */ + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + + if (mContainerActivity.getStorageManager() != null) { + FileMenuFilter mf = new FileMenuFilter( + getFile(), + mContainerActivity.getStorageManager().getAccount(), + mContainerActivity, + getActivity() + ); + mf.filter(menu); + } + + // additional restriction for this fragment + MenuItem item = menu.findItem(R.id.action_rename_file); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + // additional restriction for this fragment + item = menu.findItem(R.id.action_move); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + // this one doesn't make sense since the file has to be down in order to be previewed + item = menu.findItem(R.id.action_download_file); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + item = menu.findItem(R.id.action_sync_file); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + item = menu.findItem(R.id.action_sync_account); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_share_file: { + mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile()); + return true; + } + case R.id.action_unshare_file: { + mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile()); + return true; + } + case R.id.action_open_file_with: { + openFile(); + return true; + } + case R.id.action_remove_file: { + RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile()); + dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION); + return true; + } + case R.id.action_see_details: { + seeDetails(); + return true; + } + case R.id.action_send_file: { + sendFile(); + return true; + } + case R.id.action_sync_file: { + mContainerActivity.getFileOperationsHelper().syncFile(getFile()); + return true; + } + + default: + return false; + } + } + + /** + * Update the file of the fragment with file value + * + * @param file The new file to set + */ + public void updateFile(OCFile file) { + setFile(file); + } + + private void sendFile() { + mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile()); + } + + private void seeDetails() { + mContainerActivity.showDetails(getFile()); + } + + @Override + public void onPause() { + Log_OC.e(TAG, "onPause"); + super.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + Log_OC.e(TAG, "onResume"); + } + + @Override + public void onDestroy() { + Log_OC.e(TAG, "onDestroy"); + super.onDestroy(); + } + + @Override + public void onStop() { + super.onStop(); + Log_OC.e(TAG, "onStop"); + if (mTextLoadTask != null) + mTextLoadTask.cancel(Boolean.TRUE); + } + + /** + * Opens the previewed file with an external application. + */ + private void openFile() { + mContainerActivity.getFileOperationsHelper().openFile(getFile()); + finish(); + } + + /** + * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewTextFragment} to be previewed. + * + * @param file File to test if can be previewed. + * @return 'True' if the file can be handled by the fragment. + */ + public static boolean canBePreviewed(OCFile file) { + return (file != null && file.isDown() && file.isText()); + } + + /** + * Finishes the preview + */ + private void finish() { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + getActivity().onBackPressed(); + } + }); + } +}