diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 843db7d74e..c031d0c77b 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -963,20 +963,12 @@ public final class ThumbnailsCacheManager { thumbnail = addThumbnailToCache(imageKey, bitmap, file.getPath(), px, px); } } else if (Type.VIDEO == type) { - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - try { + try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) { retriever.setDataSource(file.getAbsolutePath()); thumbnail = retriever.getFrameAtTime(-1); } catch (Exception ex) { // can't create a bitmap Log_OC.w(TAG, "Failed to create bitmap from video " + file.getAbsolutePath()); - } finally { - try { - retriever.release(); - } catch (RuntimeException | IOException ex) { - // Ignore failure at this point. - Log_OC.w(TAG, "Failed release MediaMetadataRetriever for " + file.getAbsolutePath()); - } } if (thumbnail != null) { diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 4a1216334c..4a40204b58 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -953,15 +953,11 @@ public class UploadFileOperation extends SyncOperation { File temporalFile = null; File originalFile = new File(mOriginalStoragePath); File expectedFile = null; - FileLock fileLock = null; - FileChannel channel = null; - long size; try { // check conditions result = checkConditions(originalFile); - if (result != null) { return result; } @@ -983,107 +979,121 @@ public class UploadFileOperation extends SyncOperation { // Get the last modification date of the file from the file system long lastModifiedTimestamp = originalFile.lastModified() / 1000; - final Long creationTimestamp = FileUtil.getCreationTimestamp(originalFile); - try { - channel = new RandomAccessFile(mFile.getStoragePath(), "rw").getChannel(); - fileLock = channel.tryLock(); - } catch (FileNotFoundException e) { - // this basically means that the file is on SD card - // try to copy file to temporary dir if it doesn't exist - String temporalPath = FileStorageUtils.getInternalTemporalPath(user.getAccountName(), mContext) + - mFile.getRemotePath(); - mFile.setStoragePath(temporalPath); - temporalFile = new File(temporalPath); + // Initialize channel and fileLock in try-with-resources + try ( + FileChannel channel = new RandomAccessFile(mFile.getStoragePath(), "rw").getChannel(); + FileLock fileLock = channel.tryLock() + ) { + if (fileLock == null) { + // Handle the case when the file lock cannot be acquired + String temporalPath = FileStorageUtils.getInternalTemporalPath(user.getAccountName(), mContext) + mFile.getRemotePath(); + mFile.setStoragePath(temporalPath); + temporalFile = new File(temporalPath); - Files.deleteIfExists(Paths.get(temporalPath)); - result = copy(originalFile, temporalFile); + Files.deleteIfExists(Paths.get(temporalPath)); + result = copy(originalFile, temporalFile); - if (result.isSuccess()) { - if (temporalFile.length() == originalFile.length()) { - channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel(); - fileLock = channel.tryLock(); + if (result.isSuccess()) { + if (temporalFile.length() == originalFile.length()) { + // Acquire lock on temporary file + try (FileChannel tempChannel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel(); + FileLock tempFileLock = tempChannel.tryLock()) { + if (tempFileLock != null) { + // Use the temporary channel for the upload + size = tempChannel.size(); + updateSize(size); + + // Perform the upload operation + if (size > ChunkedFileUploadRemoteOperation.CHUNK_SIZE_MOBILE) { + boolean onWifiConnection = connectivityService.getConnectivity().isWifi(); + mUploadOperation = new ChunkedFileUploadRemoteOperation( + mFile.getStoragePath(), + mFile.getRemotePath(), + mFile.getMimeType(), + mFile.getEtagInConflict(), + lastModifiedTimestamp, + creationTimestamp, + onWifiConnection, + mDisableRetries + ); + } else { + mUploadOperation = new UploadFileRemoteOperation( + mFile.getStoragePath(), + mFile.getRemotePath(), + mFile.getMimeType(), + mFile.getEtagInConflict(), + lastModifiedTimestamp, + creationTimestamp, + mDisableRetries + ); + } + + + if (result.isSuccess() && mUploadOperation != null) { + result = mUploadOperation.execute(client); + if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) { + result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); + } + } + } else { + result = new RemoteOperationResult(ResultCode.LOCK_FAILED); + } + } + } else { + result = new RemoteOperationResult(ResultCode.LOCK_FAILED); + } + } + } else { + size = channel.size(); + updateSize(size); + + // Perform the upload operation + if (size > ChunkedFileUploadRemoteOperation.CHUNK_SIZE_MOBILE) { + boolean onWifiConnection = connectivityService.getConnectivity().isWifi(); + mUploadOperation = new ChunkedFileUploadRemoteOperation( + mFile.getStoragePath(), + mFile.getRemotePath(), + mFile.getMimeType(), + mFile.getEtagInConflict(), + lastModifiedTimestamp, + creationTimestamp, + onWifiConnection, + mDisableRetries + ); } else { - result = new RemoteOperationResult(ResultCode.LOCK_FAILED); + mUploadOperation = new UploadFileRemoteOperation( + mFile.getStoragePath(), + mFile.getRemotePath(), + mFile.getMimeType(), + mFile.getEtagInConflict(), + lastModifiedTimestamp, + creationTimestamp, + mDisableRetries + ); + } + + if (result.isSuccess() && mUploadOperation != null) { + result = mUploadOperation.execute(client); + if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) { + result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); + } } } + } catch (FileNotFoundException e) { + Log_OC.d(TAG, mOriginalStoragePath + " not exists anymore"); + result = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND); + } catch (OverlappingFileLockException e) { + Log_OC.d(TAG, "Overlapping file lock exception"); + result = new RemoteOperationResult(ResultCode.LOCK_FAILED); + } catch (Exception e) { + result = new RemoteOperationResult(e); } - try { - size = channel.size(); - } catch (Exception e1) { - size = new File(mFile.getStoragePath()).length(); - } - - updateSize(size); - - // perform the upload - if (size > ChunkedFileUploadRemoteOperation.CHUNK_SIZE_MOBILE) { - boolean onWifiConnection = connectivityService.getConnectivity().isWifi(); - - mUploadOperation = new ChunkedFileUploadRemoteOperation(mFile.getStoragePath(), - mFile.getRemotePath(), - mFile.getMimeType(), - mFile.getEtagInConflict(), - lastModifiedTimestamp, - creationTimestamp, - onWifiConnection, - mDisableRetries); - } else { - mUploadOperation = new UploadFileRemoteOperation(mFile.getStoragePath(), - mFile.getRemotePath(), - mFile.getMimeType(), - mFile.getEtagInConflict(), - lastModifiedTimestamp, - creationTimestamp, - mDisableRetries); - } - - for (OnDatatransferProgressListener mDataTransferListener : mDataTransferListeners) { - mUploadOperation.addDataTransferProgressListener(mDataTransferListener); - } - - if (mCancellationRequested.get()) { - throw new OperationCancelledException(); - } - - if (result.isSuccess() && mUploadOperation != null) { - result = mUploadOperation.execute(client); - - /// move local temporal file or original file to its corresponding - // location in the Nextcloud local folder - if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) { - result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); - } - } - } catch (FileNotFoundException e) { - Log_OC.d(TAG, mOriginalStoragePath + " not exists anymore"); - result = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND); - } catch (OverlappingFileLockException e) { - Log_OC.d(TAG, "Overlapping file lock exception"); - result = new RemoteOperationResult(ResultCode.LOCK_FAILED); - } catch (Exception e) { - result = new RemoteOperationResult(e); - } finally { + // Finalize cleanup mUploadStarted.set(false); - if (fileLock != null) { - try { - fileLock.release(); - } catch (IOException e) { - Log_OC.e(TAG, "Failed to unlock file with path " + mOriginalStoragePath); - } - } - - if (channel != null) { - try { - channel.close(); - } catch (IOException e) { - Log_OC.w(TAG, "Failed to close file channel"); - } - } - if (temporalFile != null && !originalFile.equals(temporalFile)) { temporalFile.delete(); } @@ -1093,6 +1103,8 @@ public class UploadFileOperation extends SyncOperation { } logResult(result, mOriginalStoragePath, mRemotePath); + } catch (Exception e) { + result = new RemoteOperationResult(e); } if (result.isSuccess()) { @@ -1101,7 +1113,7 @@ public class UploadFileOperation extends SyncOperation { getStorageManager().saveConflict(mFile, mFile.getEtagInConflict()); } - // delete temporal file + // Delete temporal file if (temporalFile != null && temporalFile.exists() && !temporalFile.delete()) { Log_OC.e(TAG, "Could not delete temporal file " + temporalFile.getAbsolutePath()); } @@ -1109,6 +1121,7 @@ public class UploadFileOperation extends SyncOperation { return result; } + private void updateSize(long size) { OCUpload ocUpload = uploadsStorageManager.getUploadById(getOCUploadId()); if (ocUpload != null) { @@ -1532,22 +1545,16 @@ public class UploadFileOperation extends SyncOperation { if (!sourceFile.renameTo(targetFile)) { // try to copy and then delete targetFile.createNewFile(); - FileChannel inChannel = new FileInputStream(sourceFile).getChannel(); - FileChannel outChannel = new FileOutputStream(targetFile).getChannel(); - try { + try ( + FileChannel inChannel = new FileInputStream(sourceFile).getChannel(); + FileChannel outChannel = new FileOutputStream(targetFile).getChannel() + ) { inChannel.transferTo(0, inChannel.size(), outChannel); sourceFile.delete(); } catch (Exception e) { mFile.setStoragePath(""); // forget the local file // by now, treat this as a success; the file was uploaded // the best option could be show a warning message - } finally { - if (inChannel != null) { - inChannel.close(); - } - if (outChannel != null) { - outChannel.close(); - } } } diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java b/app/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java index b89e2b3013..2af0595e88 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java @@ -117,9 +117,6 @@ public class CopyAndUploadContentUrisTask extends AsyncTask 0) { - outputStream.write(buffer, 0, count); - } - - if (lastModified != 0) { - try { - if (!cacheFile.setLastModified(lastModified)) { - Log_OC.w(TAG, "Could not change mtime of cacheFile"); - } - } catch (SecurityException e) { - Log_OC.e(TAG, "Not enough permissions to change mtime of cacheFile", e); - } catch (IllegalArgumentException e) { - Log_OC.e(TAG, "Could not change mtime of cacheFile, mtime is negativ: "+lastModified, e); + try (InputStream inputStream = leakedContentResolver.openInputStream(currentUri); + FileOutputStream outputStream = new FileOutputStream(fullTempPath)) { + byte[] buffer = new byte[4096]; + int count; + while ((count = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, count); } + + if (lastModified != 0) { + try { + if (!cacheFile.setLastModified(lastModified)) { + Log_OC.w(TAG, "Could not change mtime of cacheFile"); + } + } catch (SecurityException e) { + Log_OC.e(TAG, "Not enough permissions to change mtime of cacheFile", e); + } catch (IllegalArgumentException e) { + Log_OC.e(TAG, "Could not change mtime of cacheFile, mtime is negativ: " + lastModified, e); + } + } + + requestUpload(user, fullTempPath, currentRemotePath, behaviour); + fullTempPath = null; } - requestUpload( - user, - fullTempPath, - currentRemotePath, - behaviour - ); - fullTempPath = null; } - result = ResultCode.OK; } catch (ArrayIndexOutOfBoundsException e) { @@ -206,7 +194,7 @@ public class CopyAndUploadContentUrisTask extends AsyncTask - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ -package com.owncloud.android.ui.decoration; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.util.DisplayMetrics; -import android.view.View; - -import androidx.recyclerview.widget.DividerItemDecoration; -import androidx.recyclerview.widget.RecyclerView; - -/** - * DividerItemDecoration based on {@link DividerItemDecoration} adding a 72dp left padding. - */ -public class SimpleListItemDividerDecoration extends DividerItemDecoration { - private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; - - private final Rect bounds = new Rect(); - private Drawable divider; - private int leftPadding; - - /** - * Default divider will be used - */ - public SimpleListItemDividerDecoration(Context context) { - super(context, DividerItemDecoration.VERTICAL); - final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS); - divider = styledAttributes.getDrawable(0); - leftPadding = Math.round(72 * (context.getResources().getDisplayMetrics().xdpi / DisplayMetrics.DENSITY_DEFAULT)); - styledAttributes.recycle(); - } - - @Override - public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) { - canvas.save(); - final int right; - //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides. - if (parent.getClipToPadding()) { - right = parent.getWidth() - parent.getPaddingRight(); - canvas.clipRect(leftPadding, parent.getPaddingTop(), right, - parent.getHeight() - parent.getPaddingBottom()); - } else { - right = parent.getWidth(); - } - - final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = parent.getChildAt(i); - parent.getDecoratedBoundsWithMargins(child, bounds); - final int bottom = bounds.bottom + Math.round(child.getTranslationY()); - final int top = bottom - 1; - - if (divider != null) { - divider.setBounds(leftPadding, top, right, bottom); - divider.draw(canvas); - } - } - canvas.restore(); - } -} diff --git a/app/src/main/java/third_parties/sufficientlysecure/AndroidCalendar.java b/app/src/main/java/third_parties/sufficientlysecure/AndroidCalendar.java index e85e63cb42..098421035c 100644 --- a/app/src/main/java/third_parties/sufficientlysecure/AndroidCalendar.java +++ b/app/src/main/java/third_parties/sufficientlysecure/AndroidCalendar.java @@ -113,11 +113,9 @@ public class AndroidCalendar { private static boolean missing(ContentResolver resolver, Uri uri) { // Determine if a provider is missing - ContentProviderClient provider = resolver.acquireContentProviderClient(uri); - if (provider != null) { - provider.release(); + try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) { + return provider == null; } - return provider == null; } @Override