Browse Source

Merge pull request #1468 from nextcloud/ao-improvements

AutoUpload improvements
Andy Scherzinger 7 years ago
parent
commit
a65e0f46a5

+ 1 - 1
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'

+ 1 - 1
scripts/lint/lint-results.txt

@@ -1,2 +1,2 @@
 DO NOT TOUCH; GENERATED BY DRONE
-      <span class="mdl-layout-title">Lint Report: 1 error and 515 warnings</span>
+      <span class="mdl-layout-title">Lint Report: 1 error and 512 warnings</span>

+ 3 - 0
src/main/AndroidManifest.xml

@@ -235,6 +235,9 @@
         <receiver android:name=".files.BootupBroadcastReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
+                <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
+                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
+                <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
             </intent-filter>
         </receiver>
 

+ 49 - 38
src/main/java/com/owncloud/android/MainApp.java

@@ -125,26 +125,7 @@ public class MainApp extends MultiDexApplication {
             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 class MainApp extends MultiDexApplication {
         });
     }
 
+    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 class MainApp extends MultiDexApplication {
         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 @@ public class MainApp extends MultiDexApplication {
 
                 // 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 class MainApp extends MultiDexApplication {
             }
     }
 
-    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 @@ public class MainApp extends MultiDexApplication {
                 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 @@ public class MainApp extends MultiDexApplication {
         }).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<SyncedFolder> syncedFolderList = syncedFolderProvider.getSyncedFolders();
             Map<Pair<String, String>, Long> syncedFolders = new HashMap<>();
@@ -454,7 +465,7 @@ public class MainApp extends MultiDexApplication {
             if (ids.size() > 0) {
                 syncedFolderProvider.deleteSyncedFoldersNotInList(mContext, ids);
             } else {
-                PreferenceManager.setLegacyClean(this, true);
+                PreferenceManager.setLegacyClean(context, true);
             }
         }
     }

+ 1 - 0
src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java

@@ -154,6 +154,7 @@ public class UploadsStorageManager extends Observable {
         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,

+ 4 - 4
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.BroadcastReceiver;
 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();
     }
 
 }

+ 6 - 0
src/main/java/com/owncloud/android/files/services/FileDownloader.java

@@ -28,6 +28,7 @@ import android.app.NotificationManager;
 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.notifications.NotificationUtils;
 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 class FileDownloader extends Service
 
         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

+ 6 - 0
src/main/java/com/owncloud/android/files/services/FileUploader.java

@@ -33,6 +33,7 @@ import android.app.PendingIntent;
 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.FileActivity;
 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 class FileUploader extends Service
 
         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(

+ 62 - 44
src/main/java/com/owncloud/android/operations/UploadFileOperation.java

@@ -28,6 +28,7 @@ import com.evernote.android.job.util.Device;
 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 @@ public class UploadFileOperation extends SyncOperation {
         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 @@ public class UploadFileOperation extends SyncOperation {
             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 @@ public class UploadFileOperation extends SyncOperation {
                 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 @@ public class UploadFileOperation extends SyncOperation {
             if (temporalFile != null && !originalFile.equals(temporalFile)) {
                 temporalFile.delete();
             }
+
             if (result == null) {
                 result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
             }

+ 6 - 1
src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java

@@ -237,7 +237,11 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
 
             // 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 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
             /// Reset fields visibility
             uploadDateTextView.setVisibility(View.VISIBLE);
             pathTextView.setVisibility(View.VISIBLE);
+
             fileSizeTextView.setVisibility(View.VISIBLE);
             accountNameTextView.setVisibility(View.VISIBLE);
             statusTextView.setVisibility(View.VISIBLE);

+ 1 - 1
src/main/res/layout/file_details_share_user_item.xml

@@ -31,7 +31,7 @@
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:textSize="16dip"
+            android:textSize="16sp"
             android:text="@string/username"
             android:id="@+id/userOrGroupName"
             android:layout_margin="12dp"

+ 1 - 1
src/main/res/layout/fingerprintlock.xml

@@ -49,7 +49,7 @@
             android:padding="8dp"
             android:text="@string/fingerprint_scan_finger"
             android:textColor="@android:color/black"
-            android:textSize="32dp"/>
+            android:textSize="32sp"/>
 
         <ImageView
             android:id="@+id/fingerprinticon"

+ 2 - 2
src/main/res/layout/upload_list_item.xml

@@ -89,7 +89,7 @@
             android:textColor="@color/list_item_lastmod_and_filesize_text"
             android:maxLines="1"
             android:text="@string/auth_username"
-            android:textSize="@dimen/upload_list_item_text_size_independent"/>
+            android:textSize="@dimen/upload_list_item_text_size"/>
 
         <TextView
             android:id="@+id/upload_remote_path"
@@ -99,7 +99,7 @@
             android:ellipsize="middle"
             android:singleLine="true"
             android:text="@string/instant_upload_path"
-            android:textSize="@dimen/upload_list_item_text_size_independent"/>
+            android:textSize="@dimen/upload_list_item_text_size"/>
 
     </LinearLayout>
 

+ 1 - 2
src/main/res/values/dims.xml

@@ -71,7 +71,7 @@
     <dimen name="alternate_fragment_margin">15dp</dimen>
     <dimen name="file_download_fragment_display_text_margin">40dp</dimen>
     <dimen name="drawer_width">240dp</dimen>
-    <dimen name="grid_item_text_size">16dip</dimen>
+    <dimen name="grid_item_text_size">16sp</dimen>
     <dimen name="list_fragment_column_width">100dp</dimen>
     <dimen name="list_fragment_spacing">2dp</dimen>
     <dimen name="seek_bar_height">32dp</dimen>
@@ -83,7 +83,6 @@
     <dimen name="scroll_view_height">180dp</dimen>
     <dimen name="upload_list_item_frame_layout_width">60dp</dimen>
     <dimen name="upload_list_item_text_size">12sp</dimen>
-    <dimen name="upload_list_item_text_size_independent">12dip</dimen>
     <dimen name="upload_list_item_image_size">35dp</dimen>
     <dimen name="uploader_list_item_layout_image_margin">12dp</dimen>
     <dimen name="media_grid_spacing">2dp</dimen>

+ 3 - 0
src/main/res/values/strings.xml

@@ -695,4 +695,7 @@
     <string name="whats_new_fingerprint_content">Use your fingerprint to unlock the app</string>
     <string name="fallback_weblogin_back">BACK</string>
     <string name="fallback_weblogin_text">Go back to old login method</string>
+
+    <string name="foreground_service_upload">Uploading files&#8230;</string>
+    <string name="foreground_service_download">Downloading files&#8230;</string>
 </resources>