Browse Source

Merge pull request #171 from nextcloud/uploadWhenCharging

Upload when charging
Andy Scherzinger 8 years ago
parent
commit
32be5dfeb3

+ 3 - 1
AndroidManifest.xml

@@ -189,12 +189,14 @@
 
         <activity android:name=".ui.errorhandling.ErrorShowActivity" />
         <activity android:name=".ui.activity.UploadListActivity" />
-        
+
         <receiver android:name=".files.services.ConnectivityActionReceiver"
 		    android:enabled="true" android:label="ConnectivityActionReceiver">
 		    <intent-filter>
 		        <!--action android:name="android.net.conn.CONNECTIVITY_CHANGE"/-->
 		        <action android:name="android.net.wifi.STATE_CHANGE"/>
+                <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
+                <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
 		    </intent-filter>
 		</receiver>
 		<receiver android:name=".files.InstantUploadBroadcastReceiver">

+ 0 - 10
res/values-tzl/strings.xml

@@ -1,10 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<resources>
-  <!--TODO re-enable when server-side folder size calculation is available   
-    	<item>Biggest - Smallest</item>-->
-  <!--TODO re-enable when "Accounts" is available in Navigation Drawer-->
-  <!--<string name="drawer_item_accounts">Accounts</string>-->
-  <!--TODO re-enable when "On Device" is available
-    <string name="drawer_item_on_device">On device</string>-->
-  <string name="empty"></string>
-</resources>

+ 3 - 0
res/values/strings.xml

@@ -295,6 +295,8 @@
 
     <string name="instant_upload_on_wifi">Upload pictures via wifi only</string>
     <string name="instant_video_upload_on_wifi">Upload videos via wifi only</string>
+    <string name="instant_video_upload_on_charging">Upload when charging only</string>
+    <string name="instant_upload_on_charging">Upload when charging only</string>
     <string name="instant_upload_path">/InstantUpload</string>
     <string name="conflict_title">File conflict</string>
     <string name="conflict_message">Which files do you want to keep? If you select both versions, the local file will have a number added to its name.</string>
@@ -460,6 +462,7 @@
     <string name="local_file_not_found_toast">The file was not found in the local file system</string>
     <string name="confirmation_remove_files_alert">Do you really want to remove the selected items?</string>
     <string name="confirmation_remove_folders_alert">Do you really want to remove the selected items and their contents?</string>
+    <string name="uploads_view_upload_status_waiting_for_charging">Waiting for device charging</string>
     <string name="actionbar_search">Search</string>
     <plurals name="items_selected_count">
         <!--

+ 17 - 8
res/xml/preferences.xml

@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2015 ownCloud Inc.
+  Copyright (C) 2012-2013 ownCloud Inc.
 
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2,
@@ -31,11 +31,17 @@
                             android:summary="@string/prefs_instant_upload_path_use_subfolders_summary"
 							android:key="instant_upload_path_use_subfolders" />
 	    <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
-	        				android:title="@string/instant_upload_on_wifi"
-	        				android:key="instant_upload_on_wifi"/>
-	    <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle android:key="instant_video_uploading"
-	                        android:title="@string/prefs_instant_video_upload"
-	                        android:summary="@string/prefs_instant_video_upload_summary" />
+			android:dependency="instant_uploading"
+			android:disableDependentsState="true"
+	        android:title="@string/instant_upload_on_wifi"
+	        android:key="instant_upload_on_wifi"/>
+		<com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
+			android:title="@string/instant_upload_on_charging"
+			android:key="instant_upload_on_charging"/>
+		<com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
+			android:key="instant_video_uploading"
+	        android:title="@string/prefs_instant_video_upload"
+	        android:summary="@string/prefs_instant_video_upload_summary" />
 	    <com.owncloud.android.ui.PreferenceWithLongSummary
 							android:title="@string/prefs_instant_video_upload_path_title"
 							android:key="instant_video_upload_path" />
@@ -46,6 +52,9 @@
 	    <com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
 	        				android:title="@string/instant_video_upload_on_wifi"
 	        				android:key="instant_video_upload_on_wifi"/>
+		<com.owncloud.android.ui.CheckBoxPreferenceWithLongTitle
+			android:title="@string/instant_video_upload_on_charging"
+			android:key="instant_video_upload_on_charging"/>
 		<com.owncloud.android.ui.dialog.OwnCloudListPreference android:key="prefs_instant_behaviour"
 			android:dialogTitle="@string/prefs_instant_behaviour_dialogTitle"
 			android:title="@string/prefs_instant_behaviour_title"
@@ -67,7 +76,7 @@
 	<PreferenceCategory android:title="@string/prefs_category_details">
 		<android.preference.CheckBoxPreference android:title="@string/prefs_passcode" android:key="set_pincode" />
 	</PreferenceCategory>
-	
+
 	<PreferenceCategory android:title="@string/prefs_category_more" android:key="more">
 		<Preference android:title="@string/prefs_help" android:key="help" />
 		<Preference android:title="@string/prefs_recommend" android:key="recommend" />
@@ -76,6 +85,6 @@
 		<Preference android:title="@string/prefs_imprint" android:key="imprint" />
 		<Preference android:title="@string/about_title" android:id="@+id/about_app" android:key="about_app" />
 	</PreferenceCategory>
-    
+
 
 </PreferenceScreen>

+ 11 - 7
src/com/owncloud/android/datamodel/UploadsStorageManager.java

@@ -365,7 +365,8 @@ public class UploadsStorageManager extends Observable {
     public OCUpload[] getCurrentAndPendingUploads() {
         return getUploads(
             ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value + " OR " +
-            ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_WIFI.getValue(),
+            ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_WIFI.getValue() + " OR " +
+            ProviderTableMeta.UPLOADS_LAST_RESULT + "==" + UploadResult.DELAYED_FOR_CHARGING.getValue(),
             null
         );
     }
@@ -388,10 +389,11 @@ public class UploadsStorageManager extends Observable {
      * Get all failed uploads, except for those that were not performed due to lack of Wifi connection
      * @return      Array of failed uploads, except for those that were not performed due to lack of Wifi connection.
      */
-    public OCUpload[] getFailedButNotDelayedForWifiUploads() {
+    public OCUpload[] getFailedButNotDelayedUploads() {
         return getUploads(
             ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + " AND " +
-                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue(),
+                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + " AND " +
+                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(),
             null
         );
     }
@@ -400,11 +402,12 @@ public class UploadsStorageManager extends Observable {
         return mContentResolver;
     }
 
-    public long clearFailedButNotDelayedForWifiUploads() {
+    public long clearFailedButNotDelayedUploads() {
         long result = getDB().delete(
             ProviderTableMeta.CONTENT_URI_UPLOADS,
             ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + " AND " +
-                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue(),
+                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + " AND " +
+                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(),
             null
         );
         Log_OC.d(TAG, "delete all failed uploads but those delayed for Wifi");
@@ -426,14 +429,15 @@ public class UploadsStorageManager extends Observable {
         return result;
     }
 
-    public long clearAllFinishedButNotDelayedForWifiUploads() {
+    public long clearAllFinishedButNotDelayedUploads() {
         String[] whereArgs = new String[2];
         whereArgs[0] = String.valueOf(UploadStatus.UPLOAD_SUCCEEDED.value);
         whereArgs[1] = String.valueOf(UploadStatus.UPLOAD_FAILED.value);
         long result = getDB().delete(
                 ProviderTableMeta.CONTENT_URI_UPLOADS,
                 ProviderTableMeta.UPLOADS_STATUS + "=? OR " + ProviderTableMeta.UPLOADS_STATUS + "=? AND " +
-                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue(),
+                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() + " AND " +
+                ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue(),
                 whereArgs
         );
         Log_OC.d(TAG, "delete all finished uploads");

+ 6 - 0
src/com/owncloud/android/db/PreferenceManager.java

@@ -67,6 +67,12 @@ public abstract class PreferenceManager {
     public static boolean instantVideoUploadViaWiFiOnly(Context context) {
         return getDefaultSharedPreferences(context).getBoolean(PREF__INSTANT_VIDEO_UPLOAD_ON_WIFI, false);
     }
+    public static boolean instantPictureUploadWhenChargingOnly(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_upload_on_charging", false);
+    }
+    public static boolean instantVideoUploadWhenChargingOnly(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_video_upload_on_charging", false);
+    }
 
     /**
      * Gets the path where the user selected to do the last upload of a file shared from other app.

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

@@ -34,7 +34,8 @@ public enum UploadResult {
     CANCELLED(7),
     FILE_NOT_FOUND(8),
     DELAYED_FOR_WIFI(9),
-    SERVICE_INTERRUPTED(10);
+    SERVICE_INTERRUPTED(10),
+    DELAYED_FOR_CHARGING(11);
 
     private final int value;
 
@@ -71,6 +72,8 @@ public enum UploadResult {
                 return DELAYED_FOR_WIFI;
             case 10:
                 return SERVICE_INTERRUPTED;
+            case 11:
+                return DELAYED_FOR_CHARGING;
         }
         return null;
     }
@@ -105,6 +108,8 @@ public enum UploadResult {
                 return CANCELLED;
             case DELAYED_FOR_WIFI:
                 return DELAYED_FOR_WIFI;
+            case DELAYED_FOR_CHARGING:
+                return DELAYED_FOR_CHARGING;
             case UNKNOWN_ERROR:
                 if (result.getException() instanceof java.io.FileNotFoundException) {
                     return FILE_ERROR;

+ 1 - 1
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java

@@ -72,7 +72,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
     }
 
     /**
-     * Because we support NEW_PHOTO_ACTION and NEW_PHOTO_ACTION_UNOFFICIAL it can happen that 
+     * Because we support NEW_PHOTO_ACTION and NEW_PHOTO_ACTION_UNOFFICIAL it can happen that
      * handleNewPictureAction is called twice for the same photo. Use this simple static variable to
      * remember last uploaded photo to filter duplicates. Must not be null!
      */

+ 18 - 0
src/com/owncloud/android/files/services/ConnectivityActionReceiver.java

@@ -70,6 +70,24 @@ public class ConnectivityActionReceiver extends BroadcastReceiver {
             Log_OC.v(TAG, "no extras");
         }
 
+        if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
+            // for the moment, only recovery of instant uploads, similar to behaviour in release 1.9.1
+            if (
+                    (PreferenceManager.instantPictureUploadEnabled(context) &&
+                            PreferenceManager.instantPictureUploadWhenChargingOnly(context)) ||
+                            (PreferenceManager.instantVideoUploadEnabled(context) &&
+                                    PreferenceManager.instantVideoUploadWhenChargingOnly(context))
+                    ) {
+                Log_OC.d(TAG, "Requesting retry of instant uploads (& friends) due to charging");
+                FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
+                requester.retryFailedUploads(
+                        context,
+                        null,
+                        UploadResult.DELAYED_FOR_CHARGING   // for the rest of enqueued when Wifi fell
+                );
+            }
+        }
+
         /**
          * There is an interesting mess to process WifiManager.NETWORK_STATE_CHANGED_ACTION and
          * ConnectivityManager.CONNECTIVITY_ACTION in a simple and reliable way.

+ 2 - 1
src/com/owncloud/android/files/services/FileUploader.java

@@ -1030,7 +1030,8 @@ public class FileUploader extends Service
 
         // Show the result: success or fail notification
         if (!uploadResult.isCancelled() &&
-            !uploadResult.getCode().equals(ResultCode.DELAYED_FOR_WIFI)) {
+            !uploadResult.getCode().equals(ResultCode.DELAYED_FOR_WIFI) &&
+            !uploadResult.getCode().equals(ResultCode.DELAYED_FOR_CHARGING)) {
 
             int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker :
                     R.string.uploader_upload_failed_ticker;

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

@@ -300,6 +300,12 @@ public class UploadFileOperation extends SyncOperation {
                 return new RemoteOperationResult(ResultCode.DELAYED_FOR_WIFI);
             }
 
+            // Check if charging conditions are met and delays the upload otherwise
+            if (delayForCharging()){
+                Log_OC.d(TAG, "Upload delayed until the device is charging: " + getRemotePath());
+                return new RemoteOperationResult(ResultCode.DELAYED_FOR_CHARGING);
+            }
+
             /// check if the file continues existing before schedule the operation
             if (!originalFile.exists()) {
                 Log_OC.d(TAG, mOriginalStoragePath.toString() + " not exists anymore");
@@ -468,6 +474,22 @@ public class UploadFileOperation extends SyncOperation {
         );
     }
 
+    /**
+     * Check if upload should be delayed due to not charging
+     *
+     * @return      'True' if the upload was delayed until device is charging, 'false' otherwise.
+     */
+    private boolean delayForCharging() {
+        boolean delayInstantPicture = isInstantPicture() &&
+                PreferenceManager.instantPictureUploadWhenChargingOnly(mContext);
+
+        boolean delayInstantVideo = isInstantVideo() &&
+                PreferenceManager.instantVideoUploadViaWiFiOnly(mContext);
+
+        return ((delayInstantPicture || delayInstantVideo)
+                && !ConnectivityUtils.isCharging(mContext));
+    }
+
 
     /**
      * Checks the existence of the folder where the current file will be uploaded both

+ 8 - 0
src/com/owncloud/android/ui/activity/Preferences.java

@@ -82,11 +82,13 @@ public class Preferences extends PreferenceActivity {
     private Preference mPrefInstantUploadBehaviour;
     private Preference mPrefInstantUploadPath;
     private Preference mPrefInstantUploadUseSubfolders;
+    private Preference mPrefInstantPictureUploadOnlyOnCharging;
     private Preference mPrefInstantUploadPathWiFi;
     private Preference mPrefInstantVideoUpload;
     private Preference mPrefInstantVideoUploadPath;
     private Preference mPrefInstantVideoUploadUseSubfolders;
     private Preference mPrefInstantVideoUploadPathWiFi;
+    private Preference mPrefInstantVideoUploadOnlyOnCharging;
     private String mUploadVideoPath;
 
     @SuppressWarnings("deprecation")
@@ -291,6 +293,7 @@ public class Preferences extends PreferenceActivity {
 
         mPrefInstantUploadUseSubfolders = findPreference("instant_upload_path_use_subfolders");
         mPrefInstantUploadPathWiFi =  findPreference("instant_upload_on_wifi");
+        mPrefInstantPictureUploadOnlyOnCharging = findPreference("instant_upload_on_charging");
         mPrefInstantUpload = findPreference("instant_uploading");
         
         toggleInstantPictureOptions(((CheckBoxPreference) mPrefInstantUpload).isChecked());
@@ -328,6 +331,7 @@ public class Preferences extends PreferenceActivity {
         mPrefInstantVideoUploadUseSubfolders = findPreference("instant_video_upload_path_use_subfolders");
         mPrefInstantVideoUploadPathWiFi =  findPreference("instant_video_upload_on_wifi");
         mPrefInstantVideoUpload = findPreference("instant_video_uploading");
+        mPrefInstantVideoUploadOnlyOnCharging = findPreference("instant_video_upload_on_charging");
         toggleInstantVideoOptions(((CheckBoxPreference) mPrefInstantVideoUpload).isChecked());
         
         mPrefInstantVideoUpload.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@@ -364,10 +368,12 @@ public class Preferences extends PreferenceActivity {
             mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPathWiFi);
             mPrefInstantUploadCategory.addPreference(mPrefInstantUploadPath);
             mPrefInstantUploadCategory.addPreference(mPrefInstantUploadUseSubfolders);
+            mPrefInstantUploadCategory.addPreference(mPrefInstantPictureUploadOnlyOnCharging);
         } else {
             mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPathWiFi);
             mPrefInstantUploadCategory.removePreference(mPrefInstantUploadPath);
             mPrefInstantUploadCategory.removePreference(mPrefInstantUploadUseSubfolders);
+            mPrefInstantUploadCategory.removePreference(mPrefInstantPictureUploadOnlyOnCharging);
         }
     }
     
@@ -376,10 +382,12 @@ public class Preferences extends PreferenceActivity {
             mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPathWiFi);
             mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadPath);
             mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadUseSubfolders);
+            mPrefInstantUploadCategory.addPreference(mPrefInstantVideoUploadOnlyOnCharging);
         } else {
             mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPathWiFi);
             mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadPath);
             mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadUseSubfolders);
+            mPrefInstantUploadCategory.removePreference(mPrefInstantVideoUploadOnlyOnCharging);
         }
     }
 

+ 2 - 2
src/com/owncloud/android/ui/activity/UploadListActivity.java

@@ -203,7 +203,7 @@ public class UploadListActivity extends FileActivity implements UploadListFragme
 
             case R.id.action_clear_failed_uploads:
                 storageManager = new UploadsStorageManager(getContentResolver());
-                storageManager.clearFailedButNotDelayedForWifiUploads();
+                storageManager.clearFailedButNotDelayedUploads();
                 uploadListFragment.updateUploads();
                 break;
 
@@ -215,7 +215,7 @@ public class UploadListActivity extends FileActivity implements UploadListFragme
 
             case R.id.action_clear_finished_uploads:
                 storageManager = new UploadsStorageManager(getContentResolver());
-                storageManager.clearAllFinishedButNotDelayedForWifiUploads();
+                storageManager.clearAllFinishedButNotDelayedUploads();
                 uploadListFragment.updateUploads();
                 break;
 

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

@@ -151,7 +151,7 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
         mUploadGroups[1] = new UploadGroup(mParentActivity.getString(R.string.uploads_view_group_failed_uploads)) {
             @Override
             public void refresh() {
-                items = mUploadsStorageManager.getFailedButNotDelayedForWifiUploads();
+                items = mUploadsStorageManager.getFailedButNotDelayedUploads();
                 Arrays.sort(items, comparator);
             }
 
@@ -552,6 +552,10 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
                             R.string.uploads_view_upload_status_waiting_for_wifi
                         );
                         break;
+                    case DELAYED_FOR_CHARGING:
+                        status = mParentActivity.getString(
+                                R.string.uploads_view_upload_status_waiting_for_charging);
+                        break;
                     case CONFLICT_ERROR:
                         status = mParentActivity.getString(
                             R.string.uploads_view_upload_status_conflict

+ 15 - 0
src/com/owncloud/android/utils/ConnectivityUtils.java

@@ -20,9 +20,12 @@
 package com.owncloud.android.utils;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.support.v4.net.ConnectivityManagerCompat;
+import android.os.BatteryManager;
 
 import com.owncloud.android.lib.common.utils.Log_OC;
 
@@ -46,4 +49,16 @@ public class ConnectivityUtils {
         return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
     }
 
+    public static boolean isCharging(Context context){
+        IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+        Intent batteryStatus = context.registerReceiver(null, ifilter);
+
+        int status = 0;
+        if (batteryStatus != null) {
+            status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+        }
+        return status == BatteryManager.BATTERY_STATUS_CHARGING ||
+                status == BatteryManager.BATTERY_STATUS_FULL;
+    }
+
 }