Browse Source

Merge pull request #1527 from stalker314314/stalker314314/delay-upload-in-power-save-mode

Delaying upload if device is in power save mode
Andy Scherzinger 7 years ago
parent
commit
ef7900a6a4

+ 4 - 0
src/main/java/com/owncloud/android/MainApp.java

@@ -194,6 +194,10 @@ public class MainApp extends MultiDexApplication {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
             ReceiversHelper.registerPowerChangeReceiver();
         }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            ReceiversHelper.registerPowerSaveReceiver();
+        }
     }
 
     public static Context getAppContext() {

+ 47 - 36
src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java

@@ -376,15 +376,17 @@ public class UploadsStorageManager extends Observable {
 
         if (account != null) {
             return getUploads(
-                    ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value +
-                            " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value +
+                        " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
                             "==" + UploadResult.DELAYED_FOR_WIFI.getValue() +
-                            " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                        " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
                             "==" + UploadResult.LOCK_FAILED.getValue() +
-                            " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                        " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
                             "==" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
-                            " AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
-                    new String[]{account.name}
+                        " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+                        " AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+                new String[]{account.name}
             );
         } else {
             return new OCUpload[0];
@@ -424,14 +426,16 @@ public class UploadsStorageManager extends Observable {
 
         if (account != null) {
             return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
-                            AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
-                    new String[]{account.name}
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.LOCK_FAILED.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+                new String[]{account.name}
             );
         } else {
             return new OCUpload[0];
@@ -446,9 +450,13 @@ public class UploadsStorageManager extends Observable {
     public OCUpload[] getFailedButNotDelayedUploads() {
 
         return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + AND +
-                        ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() + AND +
-                        ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + AND +
-                        ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(),
+                        ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue(),
                 null
         );
     }
@@ -463,17 +471,18 @@ public class UploadsStorageManager extends Observable {
         long result = 0;
         if (account != null) {
             result = getDB().delete(
-                    ProviderTableMeta.CONTENT_URI_UPLOADS,
-                    ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
-                    new String[]{account.name}
+                ProviderTableMeta.CONTENT_URI_UPLOADS,
+                ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.LOCK_FAILED.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+                        AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+                new String[]{account.name}
             );
         }
 
@@ -515,14 +524,16 @@ public class UploadsStorageManager extends Observable {
             result = getDB().delete(
                     ProviderTableMeta.CONTENT_URI_UPLOADS,
                     ProviderTableMeta.UPLOADS_STATUS + "=? OR " + ProviderTableMeta.UPLOADS_STATUS + "=?" +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
-                            AND +
-                            ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", whereArgs
+                            AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.LOCK_FAILED.getValue() +
+                            AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                            AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                            AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                            "<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+                            AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+                    whereArgs
             );
         }
 

+ 6 - 1
src/main/java/com/owncloud/android/db/UploadResult.java

@@ -36,7 +36,8 @@ public enum UploadResult {
     SERVICE_INTERRUPTED(10),
     DELAYED_FOR_CHARGING(11),
     MAINTENANCE_MODE(12),
-    LOCK_FAILED(13);
+    LOCK_FAILED(13),
+    DELAYED_IN_POWER_SAVE_MODE(14);
 
     private final int value;
 
@@ -80,6 +81,8 @@ public enum UploadResult {
                 return MAINTENANCE_MODE;
             case 13:
                 return LOCK_FAILED;
+            case 14:
+                return DELAYED_IN_POWER_SAVE_MODE;
         }
         return null;
     }
@@ -116,6 +119,8 @@ public enum UploadResult {
                 return DELAYED_FOR_WIFI;
             case DELAYED_FOR_CHARGING:
                 return DELAYED_FOR_CHARGING;
+            case DELAYED_IN_POWER_SAVE_MODE:
+                return DELAYED_IN_POWER_SAVE_MODE;
             case UNKNOWN_ERROR:
                 if (result.getException() instanceof java.io.FileNotFoundException) {
                     return FILE_ERROR;

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

@@ -73,6 +73,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 com.owncloud.android.utils.UploadUtils;
 
 import java.io.File;
 import java.util.AbstractList;
@@ -924,6 +925,11 @@ public class FileUploader extends Service
                             !Device.isCharging(MainApp.getAppContext())) {
                         cancel(mCurrentUpload.getAccount().name, mCurrentUpload.getFile().getRemotePath()
                                 , ResultCode.DELAYED_FOR_CHARGING);
+                    } else if (
+                            !mCurrentUpload.getIsIgnoringPowerSaveMode() &&
+                            UploadUtils.isPowerSaveMode(MainApp.getAppContext())) {
+                        cancel(mCurrentUpload.getAccount().name, mCurrentUpload.getFile().getRemotePath()
+                                , ResultCode.DELAYED_IN_POWER_SAVE_MODE);
                     }
                 }
             }
@@ -1142,6 +1148,7 @@ public class FileUploader extends Service
             !ResultCode.LOCAL_FILE_NOT_FOUND.equals(uploadResult.getCode()) &&
             !uploadResult.getCode().equals(ResultCode.DELAYED_FOR_WIFI) &&
             !uploadResult.getCode().equals(ResultCode.DELAYED_FOR_CHARGING) &&
+            !uploadResult.getCode().equals(ResultCode.DELAYED_IN_POWER_SAVE_MODE) &&
             !uploadResult.getCode().equals(ResultCode.LOCK_FAILED)    ) {
 
             int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker :

+ 8 - 0
src/main/java/com/owncloud/android/jobs/FilesSyncJob.java

@@ -47,6 +47,7 @@ import com.owncloud.android.ui.activity.Preferences;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.FilesSyncHelper;
 import com.owncloud.android.utils.MimeTypeUtil;
+import com.owncloud.android.utils.UploadUtils;
 
 import java.io.File;
 import java.io.IOException;
@@ -66,6 +67,7 @@ public class FilesSyncJob extends Job {
     public static final String TAG = "FilesSyncJob";
 
     public static final String SKIP_CUSTOM = "skipCustom";
+    public static final String OVERRIDE_POWER_SAVING = "overridePowerSaving";
 
     @NonNull
     @Override
@@ -81,6 +83,12 @@ public class FilesSyncJob extends Job {
 
         PersistableBundleCompat bundle = params.getExtras();
         final boolean skipCustom = bundle.getBoolean(SKIP_CUSTOM, false);
+        final boolean overridePowerSaving = bundle.getBoolean(OVERRIDE_POWER_SAVING, false);
+
+        // If we are in power save mode, better to postpone upload
+        if (UploadUtils.isPowerSaveMode(context) && !overridePowerSaving) {
+            return Result.SUCCESS;
+        }
 
         Resources resources = MainApp.getAppContext().getResources();
         boolean lightVersion = resources.getBoolean(R.bool.syncedFolder_light);

+ 4 - 1
src/main/java/com/owncloud/android/jobs/NContentObserverJob.java

@@ -29,6 +29,7 @@ import android.support.annotation.RequiresApi;
 import com.evernote.android.job.JobRequest;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.owncloud.android.utils.FilesSyncHelper;
+import com.owncloud.android.utils.UploadUtils;
 
 import java.util.concurrent.TimeUnit;
 
@@ -43,7 +44,8 @@ public class NContentObserverJob extends JobService {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             if (params.getJobId() == FilesSyncHelper.ContentSyncJobId && params.getTriggeredContentAuthorities()
                     != null && params.getTriggeredContentUris() != null
-                    && params.getTriggeredContentUris().length > 0) {
+                    && params.getTriggeredContentUris().length > 0
+                    && !UploadUtils.isPowerSaveMode(getApplicationContext())) {
 
                 PersistableBundleCompat persistableBundleCompat = new PersistableBundleCompat();
                 persistableBundleCompat.putBoolean(FilesSyncJob.SKIP_CUSTOM, true);
@@ -51,6 +53,7 @@ public class NContentObserverJob extends JobService {
                 new JobRequest.Builder(FilesSyncJob.TAG)
                         .setExecutionWindow(1, TimeUnit.SECONDS.toMillis(2))
                         .setBackoffCriteria(TimeUnit.SECONDS.toMillis(5), JobRequest.BackoffPolicy.LINEAR)
+                        .setExtras(persistableBundleCompat)
                         .setUpdateCurrent(false)
                         .build()
                         .schedule();

+ 12 - 0
src/main/java/com/owncloud/android/operations/UploadFileOperation.java

@@ -48,6 +48,7 @@ import com.owncloud.android.operations.common.SyncOperation;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.MimeType;
 import com.owncloud.android.utils.MimeTypeUtil;
+import com.owncloud.android.utils.UploadUtils;
 import com.owncloud.android.utils.UriUtils;
 
 import org.apache.commons.httpclient.HttpStatus;
@@ -102,6 +103,7 @@ public class UploadFileOperation extends SyncOperation {
     private int mCreatedBy = CREATED_BY_USER;
     private boolean mOnWifiOnly = false;
     private boolean mWhileChargingOnly = false;
+    private boolean mIgnoringPowerSaveMode = false;
 
     private boolean mWasRenamed = false;
     private long mOCUploadId = -1;
@@ -192,6 +194,8 @@ public class UploadFileOperation extends SyncOperation {
         mOCUploadId = upload.getUploadId();
         mCreatedBy = upload.getCreadtedBy();
         mRemoteFolderToBeCreated = upload.isCreateRemoteFolder();
+        // Ignore power save mode only if user explicitly created this upload
+        mIgnoringPowerSaveMode = (mCreatedBy == CREATED_BY_USER);
     }
 
     public boolean getIsWifiRequired() {
@@ -202,6 +206,8 @@ public class UploadFileOperation extends SyncOperation {
         return mWhileChargingOnly;
     }
 
+    public boolean getIsIgnoringPowerSaveMode() { return mIgnoringPowerSaveMode; }
+
     public Account getAccount() {
         return mAccount;
     }
@@ -347,6 +353,12 @@ public class UploadFileOperation extends SyncOperation {
                 return new RemoteOperationResult(ResultCode.DELAYED_FOR_CHARGING);
             }
 
+            // Check that device is not in power save mode
+            if (!mIgnoringPowerSaveMode && UploadUtils.isPowerSaveMode(mContext)) {
+                Log_OC.d(TAG, "Upload delayed because device is in power save mode: " + getRemotePath());
+                return new RemoteOperationResult(ResultCode.DELAYED_IN_POWER_SAVE_MODE);
+            }
+
             /// check if the file continues existing before schedule the operation
             if (!originalFile.exists()) {
                 Log_OC.d(TAG, mOriginalStoragePath + " not exists anymore");

+ 4 - 0
src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java

@@ -43,6 +43,7 @@ import android.view.View;
 import android.widget.Toast;
 
 import com.evernote.android.job.JobRequest;
+import com.evernote.android.job.util.support.PersistableBundleCompat;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.UploadsStorageManager;
 import com.owncloud.android.db.OCUpload;
@@ -237,9 +238,12 @@ public class UploadListActivity extends FileActivity implements UploadListFragme
                 break;
 
             case R.id.action_force_rescan:
+                PersistableBundleCompat persistableBundleCompat = new PersistableBundleCompat();
+                persistableBundleCompat.putBoolean(FilesSyncJob.OVERRIDE_POWER_SAVING, true);
                 new JobRequest.Builder(FilesSyncJob.TAG)
                         .setExact(1_000L)
                         .setUpdateCurrent(false)
+                        .setExtras(persistableBundleCompat)
                         .build()
                         .schedule();
                 

+ 4 - 0
src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java

@@ -571,6 +571,10 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
                     case LOCK_FAILED:
                         status = mParentActivity.getString(R.string.lock_failed);
                         break;
+                    case DELAYED_IN_POWER_SAVE_MODE:
+                        status = mParentActivity.getString(
+                                R.string.uploads_view_upload_status_waiting_exit_power_save_mode);
+                        break;
                     default:
                         status = "Naughty devs added a new fail result but no description for the user";
                         break;

+ 18 - 0
src/main/java/com/owncloud/android/utils/ReceiversHelper.java

@@ -71,4 +71,22 @@ public class ReceiversHelper {
 
         context.registerReceiver(broadcastReceiver, intentFilter);
     }
+
+    public static void registerPowerSaveReceiver() {
+        Context context = MainApp.getAppContext();
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction("android.os.action.POWER_SAVE_MODE_CHANGED");
+
+        BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (!UploadUtils.isPowerSaveMode(context)) {
+                    FilesSyncHelper.restartJobsIfNeeded();
+                }
+            }
+        };
+
+        context.registerReceiver(broadcastReceiver, intentFilter);
+    }
 }

+ 19 - 0
src/main/java/com/owncloud/android/utils/UploadUtils.java

@@ -19,12 +19,15 @@
 
 package com.owncloud.android.utils;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.State;
 import android.os.BatteryManager;
+import android.os.Build;
+import android.os.PowerManager;
 
 
 public class UploadUtils {
@@ -49,4 +52,20 @@ public class UploadUtils {
                 && cm.getActiveNetworkInfo().getState() == State.CONNECTED;
     }
 
+    /**
+     * Checks if device is in power save mode. For older devices that do not support this API, returns false.
+     * @return true if it is, false otherwise.
+     */
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static boolean isPowerSaveMode(Context context)
+    {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
+        {
+            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+            return powerManager.isPowerSaveMode();
+        }
+
+        // For older versions, we just say that device is not in power save mode
+        return false;
+    }
 }

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

@@ -172,6 +172,7 @@
     <string name="uploads_view_upload_status_service_interrupted">App terminated</string>
     <string name="uploads_view_upload_status_unknown_fail">Unknown error</string>
     <string name="uploads_view_upload_status_waiting_for_wifi">Waiting for Wi-Fi connectivity</string>
+    <string name="uploads_view_upload_status_waiting_exit_power_save_mode">Waiting to exit power save mode</string>
     <string name="uploads_view_later_waiting_to_upload">Waiting to upload</string>
     <string name="uploads_view_group_header" translatable="false">%1$s (%2$d)</string>
     <string name="downloader_download_in_progress_ticker">Downloading &#8230;</string>