diff --git a/build.gradle b/build.gradle index b122155c88cf..527aac2327ba 100644 --- a/build.gradle +++ b/build.gradle @@ -184,7 +184,7 @@ dependencies { /// dependencies for app building implementation name: 'touch-image-view' implementation 'com.android.support:multidex:1.0.2' - implementation 'com.github.nextcloud:android-library:1.0.26' + implementation 'com.github.nextcloud:android-library:1.0.28' implementation "com.android.support:support-v4:${supportLibraryVersion}" implementation "com.android.support:design:${supportLibraryVersion}" implementation 'com.jakewharton:disklrucache:2.0.2' diff --git a/scripts/lint/lint-results.txt b/scripts/lint/lint-results.txt index d551712f07d4..00f8637331de 100644 --- a/scripts/lint/lint-results.txt +++ b/scripts/lint/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 1 error and 515 warnings + Lint Report: 1 error and 512 warnings diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index f0a4268f62f4..5bb0ab5df2ce 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -235,6 +235,9 @@ + + + diff --git a/src/main/java/com/owncloud/android/MainApp.java b/src/main/java/com/owncloud/android/MainApp.java index 0f4ac2720d3f..d429b17dbe00 100644 --- a/src/main/java/com/owncloud/android/MainApp.java +++ b/src/main/java/com/owncloud/android/MainApp.java @@ -125,26 +125,7 @@ public void onCreate() { Log_OC.d("Debug", "start logging"); } - updateToAutoUpload(); - cleanOldEntries(); - updateAutoUploadEntries(); - - if (PermissionUtil.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - splitOutAutoUploadEntries(); - } else { - PreferenceManager.setAutoUploadSplitEntries(this, true); - } - - initiateExistingAutoUploadEntries(); - - FilesSyncHelper.scheduleFilesSyncIfNeeded(); - FilesSyncHelper.restartJobsIfNeeded(); - - ReceiversHelper.registerNetworkChangeReceiver(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - ReceiversHelper.registerPowerChangeReceiver(); - } + initAutoUpload(); // register global protection with pass code registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @@ -190,6 +171,31 @@ public void onActivityDestroyed(Activity activity) { }); } + public static void initAutoUpload() { + updateToAutoUpload(); + cleanOldEntries(); + updateAutoUploadEntries(); + + if (getAppContext() != null) { + if (PermissionUtil.checkSelfPermission(getAppContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + splitOutAutoUploadEntries(); + } else { + PreferenceManager.setAutoUploadSplitEntries(getAppContext(), true); + } + } + + initiateExistingAutoUploadEntries(); + + FilesSyncHelper.scheduleFilesSyncIfNeeded(); + FilesSyncHelper.restartJobsIfNeeded(); + + ReceiversHelper.registerNetworkChangeReceiver(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + ReceiversHelper.registerPowerChangeReceiver(); + } + } + public static Context getAppContext() { return MainApp.mContext; } @@ -301,12 +307,13 @@ public static String getUserAgent() { return userAgent; } - private void updateToAutoUpload() { - if (PreferenceManager.instantPictureUploadEnabled(this) || - PreferenceManager.instantPictureUploadEnabled(this)) { + private static void updateToAutoUpload() { + Context context = getAppContext(); + if (PreferenceManager.instantPictureUploadEnabled(context) || + PreferenceManager.instantPictureUploadEnabled(context)) { // remove legacy shared preferences - SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit(); + SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); editor.remove("instant_uploading") .remove("instant_video_uploading") .remove("instant_upload_path") @@ -322,16 +329,16 @@ private void updateToAutoUpload() { // show info pop-up try { - new AlertDialog.Builder(this, R.style.Theme_ownCloud_Dialog) + new AlertDialog.Builder(context, R.style.Theme_ownCloud_Dialog) .setTitle(R.string.drawer_synced_folders) .setMessage(R.string.synced_folders_new_info) .setPositiveButton(R.string.drawer_open, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // show Auto Upload - Intent folderSyncIntent = new Intent(getApplicationContext(), + Intent folderSyncIntent = new Intent(context, SyncedFoldersActivity.class); dialog.dismiss(); - startActivity(folderSyncIntent); + context.startActivity(folderSyncIntent); } }) .setNegativeButton(R.string.drawer_close, new DialogInterface.OnClickListener() { @@ -347,21 +354,23 @@ public void onClick(DialogInterface dialog, int which) { } } - private void updateAutoUploadEntries() { + private static void updateAutoUploadEntries() { // updates entries to reflect their true paths - if (!PreferenceManager.getAutoUploadPathsUpdate(this)) { + Context context = getAppContext(); + if (!PreferenceManager.getAutoUploadPathsUpdate(context)) { SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); syncedFolderProvider.updateAutoUploadPaths(mContext); } } - private void splitOutAutoUploadEntries() { - if (!PreferenceManager.getAutoUploadSplitEntries(this)) { + private static void splitOutAutoUploadEntries() { + Context context = getAppContext(); + if (!PreferenceManager.getAutoUploadSplitEntries(context)) { // magic to split out existing synced folders in two when needed // otherwise, we migrate them to their proper type (image or video) Log_OC.i(TAG, "Migrate synced_folders records for image/video split"); - ContentResolver contentResolver = this.getContentResolver(); + ContentResolver contentResolver = context.getContentResolver(); SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(contentResolver); @@ -405,11 +414,11 @@ private void splitOutAutoUploadEntries() { syncedFolderProvider.deleteSyncedFolder(id); } - PreferenceManager.setAutoUploadSplitEntries(this, true); + PreferenceManager.setAutoUploadSplitEntries(context, true); } } - private void initiateExistingAutoUploadEntries() { + private static void initiateExistingAutoUploadEntries() { new Thread(() -> { if (!PreferenceManager.getAutoUploadInit(getAppContext())) { SyncedFolderProvider syncedFolderProvider = @@ -427,13 +436,15 @@ private void initiateExistingAutoUploadEntries() { }).start(); } - private void cleanOldEntries() { + private static void cleanOldEntries() { // previous versions of application created broken entries in the SyncedFolderProvider // database, and this cleans all that and leaves 1 (newest) entry per synced folder - if (!PreferenceManager.getLegacyClean(this)) { + Context context = getAppContext(); + + if (!PreferenceManager.getLegacyClean(context)) { SyncedFolderProvider syncedFolderProvider = - new SyncedFolderProvider(MainApp.getAppContext().getContentResolver()); + new SyncedFolderProvider(context.getContentResolver()); List syncedFolderList = syncedFolderProvider.getSyncedFolders(); Map, Long> syncedFolders = new HashMap<>(); @@ -454,7 +465,7 @@ private void cleanOldEntries() { if (ids.size() > 0) { syncedFolderProvider.deleteSyncedFoldersNotInList(mContext, ids); } else { - PreferenceManager.setLegacyClean(this, true); + PreferenceManager.setLegacyClean(context, true); } } } diff --git a/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java b/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java index 9c9ebb6a37a6..9d139771be04 100644 --- a/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java +++ b/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java @@ -154,6 +154,7 @@ public int updateUpload(OCUpload ocUpload) { cv.put(ProviderTableMeta.UPLOADS_STATUS, ocUpload.getUploadStatus().value); cv.put(ProviderTableMeta.UPLOADS_LAST_RESULT, ocUpload.getLastResult().getValue()); cv.put(ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP, ocUpload.getUploadEndTimestamp()); + cv.put(ProviderTableMeta.UPLOADS_FILE_SIZE, ocUpload.getFileSize()); int result = getDB().update(ProviderTableMeta.CONTENT_URI_UPLOADS, cv, diff --git a/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java b/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java index 76d499b69135..ac4be345e938 100644 --- a/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java +++ b/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java @@ -4,6 +4,7 @@ * @author David A. Velasco * Copyright (C) 2012 Bartek Przybylski * Copyright (C) 2015 ownCloud Inc. + * Copyright (C) 2017 Mario Danic * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -24,6 +25,7 @@ import android.content.Context; import android.content.Intent; +import com.owncloud.android.MainApp; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.services.observer.FileObserverService; @@ -46,13 +48,11 @@ public class BootupBroadcastReceiver extends BroadcastReceiver { */ @Override public void onReceive(Context context, Intent intent) { - if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { - Log_OC.e(TAG, "Incorrect action sent " + intent.getAction()); - return; - } Log_OC.d(TAG, "Starting file observer service..."); Intent initObservers = FileObserverService.makeInitIntent(context); context.startService(initObservers); + + MainApp.initAutoUpload(); } } diff --git a/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/src/main/java/com/owncloud/android/files/services/FileDownloader.java index a44cc4be49b8..5cd2bc550f1a 100644 --- a/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -28,6 +28,7 @@ import android.app.PendingIntent; import android.app.Service; import android.content.Intent; +import android.graphics.BitmapFactory; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -59,6 +60,7 @@ import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.utils.ErrorMessageAdapter; +import com.owncloud.android.utils.ThemeUtils; import java.io.File; import java.util.AbstractList; @@ -127,6 +129,10 @@ public void onCreate() { mNotification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). getResources().getString(R.string.app_name)) + .setContentText(getApplicationContext().getResources().getString(R.string.foreground_service_download)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification_icon)) + .setColor(ThemeUtils.primaryColor()) .build(); // add AccountsUpdatedListener diff --git a/src/main/java/com/owncloud/android/files/services/FileUploader.java b/src/main/java/com/owncloud/android/files/services/FileUploader.java index 7e1d4de507a9..78e18d68cada 100644 --- a/src/main/java/com/owncloud/android/files/services/FileUploader.java +++ b/src/main/java/com/owncloud/android/files/services/FileUploader.java @@ -33,6 +33,7 @@ import android.app.Service; import android.content.Context; import android.content.Intent; +import android.graphics.BitmapFactory; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -71,6 +72,7 @@ import com.owncloud.android.ui.activity.UploadListActivity; import com.owncloud.android.ui.notifications.NotificationUtils; import com.owncloud.android.utils.ErrorMessageAdapter; +import com.owncloud.android.utils.ThemeUtils; import java.io.File; import java.util.AbstractList; @@ -418,6 +420,10 @@ public void onCreate() { mNotification = new NotificationCompat.Builder(this).setContentTitle(getApplicationContext(). getResources().getString(R.string.app_name)) + .setContentText(getApplicationContext().getResources().getString(R.string.foreground_service_upload)) + .setSmallIcon(R.drawable.notification_icon) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification_icon)) + .setColor(ThemeUtils.primaryColor()) .build(); int failedCounter = mUploadsStorageManager.failInProgressUploads( diff --git a/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 0e4d343aa496..9fa3f43d40d4 100644 --- a/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -28,6 +28,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; +import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.db.OCUpload; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.OwnCloudClient; @@ -319,6 +320,19 @@ protected RemoteOperationResult run(OwnCloudClient client) { File expectedFile = null; FileLock fileLock = null; + UploadsStorageManager uploadsStorageManager = new UploadsStorageManager(mContext.getContentResolver(), + mContext); + + long size = 0; + + for (OCUpload ocUpload : uploadsStorageManager.getAllStoredUploads()) { + if (ocUpload.getUploadId() == getOCUploadId()) { + ocUpload.setFileSize(size); + uploadsStorageManager.updateUpload(ocUpload); + break; + } + } + try { /// Check that connectivity conditions are met and delays the upload otherwise @@ -396,13 +410,51 @@ protected RemoteOperationResult run(OwnCloudClient client) { Long timeStampLong = originalFile.lastModified() / 1000; String timeStamp = timeStampLong.toString(); + FileChannel channel = null; + 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.getTemporalPath(mAccount.name) + mFile.getRemotePath(); + mFile.setStoragePath(temporalPath); + temporalFile = new File(temporalPath); + + Files.deleteIfExists(Paths.get(temporalPath)); + result = copy(originalFile, temporalFile); + + if (result == null) { + if (temporalFile.length() == originalFile.length()) { + channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel(); + fileLock = channel.tryLock(); + } else { + result = new RemoteOperationResult(ResultCode.LOCK_FAILED); + } + } + } + + try { + size = channel.size(); + } catch (IOException e1) { + size = new File(mFile.getStoragePath()).length(); + } + + for (OCUpload ocUpload : uploadsStorageManager.getAllStoredUploads()) { + if (ocUpload.getUploadId() == getOCUploadId()) { + ocUpload.setFileSize(size); + uploadsStorageManager.updateUpload(ocUpload); + break; + } + } + /// perform the upload if (mChunked && - (new File(mFile.getStoragePath())).length() > - ChunkedUploadRemoteFileOperation.CHUNK_SIZE) { + (size > ChunkedUploadRemoteFileOperation.CHUNK_SIZE)) { mUploadOperation = new ChunkedUploadRemoteFileOperation(mContext, mFile.getStoragePath(), mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp); } else { + mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(), mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp); } @@ -416,53 +468,18 @@ protected RemoteOperationResult run(OwnCloudClient client) { throw new OperationCancelledException(); } - FileChannel channel = null; - try { - channel = new RandomAccessFile(mFile.getStoragePath(), "rw").getChannel(); - fileLock = channel.tryLock(); - } catch (FileNotFoundException e) { - if (temporalFile == null) { - String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath(); - mFile.setStoragePath(temporalPath); - temporalFile = new File(temporalPath); - - result = copy(originalFile, temporalFile); + if (result == null || result.isSuccess() && mUploadOperation != null) { + result = mUploadOperation.execute(client); - if (result != null) { - return result; - } else { - if (temporalFile.length() == originalFile.length()) { - channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel(); - fileLock = channel.tryLock(); - } else { - while (temporalFile.length() != originalFile.length()) { - Files.deleteIfExists(Paths.get(temporalPath)); - result = copy(originalFile, temporalFile); - - if (result != null) { - return result; - } else { - channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw"). - getChannel(); - fileLock = channel.tryLock(); - } - } - } - } - } else { - channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel(); - fileLock = channel.tryLock(); + /// move local temporal file or original file to its corresponding + // location in the ownCloud local folder + if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) { + result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); } - } - - result = mUploadOperation.execute(client); - /// move local temporal file or original file to its corresponding - // location in the ownCloud 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); @@ -486,6 +503,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { if (temporalFile != null && !originalFile.equals(temporalFile)) { temporalFile.delete(); } + if (result == null) { result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR); } diff --git a/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java index ce42214e3509..77c20b277abc 100755 --- a/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java @@ -237,7 +237,11 @@ private View getView(OCUpload[] uploadsItems, int position, View convertView, Vi // file size TextView fileSizeTextView = (TextView) view.findViewById(R.id.upload_file_size); - fileSizeTextView.setText(DisplayUtils.bytesToHumanReadable(upload.getFileSize()) + ", "); + if (upload.getFileSize() != 0) { + fileSizeTextView.setText(DisplayUtils.bytesToHumanReadable(upload.getFileSize()) + ", "); + } else { + fileSizeTextView.setText(""); + } //* upload date TextView uploadDateTextView = (TextView) view.findViewById(R.id.upload_date); @@ -269,6 +273,7 @@ private View getView(OCUpload[] uploadsItems, int position, View convertView, Vi /// Reset fields visibility uploadDateTextView.setVisibility(View.VISIBLE); pathTextView.setVisibility(View.VISIBLE); + fileSizeTextView.setVisibility(View.VISIBLE); accountNameTextView.setVisibility(View.VISIBLE); statusTextView.setVisibility(View.VISIBLE); diff --git a/src/main/res/layout/file_details_share_user_item.xml b/src/main/res/layout/file_details_share_user_item.xml index 16f59de85554..e824daf2778c 100644 --- a/src/main/res/layout/file_details_share_user_item.xml +++ b/src/main/res/layout/file_details_share_user_item.xml @@ -31,7 +31,7 @@ + android:textSize="32sp"/> + android:textSize="@dimen/upload_list_item_text_size"/> + android:textSize="@dimen/upload_list_item_text_size"/> diff --git a/src/main/res/values/dims.xml b/src/main/res/values/dims.xml index 0133ffc07a3f..4fab9ef46f35 100644 --- a/src/main/res/values/dims.xml +++ b/src/main/res/values/dims.xml @@ -71,7 +71,7 @@ 15dp 40dp 240dp - 16dip + 16sp 100dp 2dp 32dp @@ -83,7 +83,6 @@ 180dp 60dp 12sp - 12dip 35dp 12dp 2dp diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 289ca1180642..69c3843be699 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -695,4 +695,7 @@ Use your fingerprint to unlock the app BACK Go back to old login method + + Uploading files… + Downloading files…