Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ interface BackgroundJobManager {
*
* This call is idempotent - there will be only one scheduled job
* regardless of number of calls.
*
* @param overridePowerSaving lets an explicitly user triggered sync run even while the device is in power
* saving mode. The worker reschedules itself without the override afterwards.
*/
fun scheduleContentObserverJob()
fun scheduleContentObserverJob(overridePowerSaving: Boolean = false)

/**
* Schedule periodic contacts backups job. Operating system will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,11 @@ internal class BackgroundJobManagerImpl(
}

@Suppress("MagicNumber")
override fun scheduleContentObserverJob() {
override fun scheduleContentObserverJob(overridePowerSaving: Boolean) {
val arguments = Data.Builder()
.putBoolean(ContentObserverWork.OVERRIDE_POWER_SAVING, overridePowerSaving)
.build()

val constrains = Constraints.Builder()
.addContentUriTrigger(MediaStore.Images.Media.INTERNAL_CONTENT_URI, true)
.addContentUriTrigger(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true)
Expand All @@ -477,6 +481,7 @@ internal class BackgroundJobManagerImpl(

val request = oneTimeRequestBuilder(ContentObserverWork::class, JOB_CONTENT_OBSERVER)
.setConstraints(constrains)
.setInputData(arguments)
.build()

workManager.enqueueUniqueWork(JOB_CONTENT_OBSERVER, ExistingWorkPolicy.REPLACE, request)
Expand Down Expand Up @@ -508,9 +513,13 @@ internal class BackgroundJobManagerImpl(
)
.build()

// an already scheduled run may still carry overridePowerSaving = false and would swallow an explicit
// user request, therefore replace it instead of keeping it
val policy = if (overridePowerSaving) ExistingWorkPolicy.REPLACE else ExistingWorkPolicy.KEEP

workManager.enqueueUniqueWork(
JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID,
ExistingWorkPolicy.KEEP,
policy,
request
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ class ContentObserverWork(

companion object {
private const val TAG = "🔍" + "ContentObserverWork"
const val OVERRIDE_POWER_SAVING = "overridePowerSaving"
}

private val overridePowerSaving: Boolean
get() = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)

override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
val workerName = BackgroundJobManagerImpl.formatClassTag(this@ContentObserverWork::class)
backgroundJobManager.logStartOfWorker(workerName)
Expand Down Expand Up @@ -72,7 +76,7 @@ class ContentObserverWork(
}

private suspend fun checkAndTriggerAutoUpload() = withContext(Dispatchers.IO) {
if (powerManagementService.isPowerSavingEnabled) {
if (powerManagementService.isPowerSavingEnabled && !overridePowerSaving) {
Log_OC.w(TAG, "⚡ Power saving mode active — skipping file sync.")
return@withContext
}
Expand Down Expand Up @@ -116,7 +120,7 @@ class ContentObserverWork(
FilesSyncHelper.startAutoUploadForEnabledSyncedFolders(
syncedFolderProvider,
backgroundJobManager,
false
overridePowerSaving
)
Log_OC.d(TAG, "✅ auto upload triggered successfully for ${contentUris.size} file(s).")
} catch (e: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ class AutoUploadWorker(
private val fileUploadHelper = FileUploadHelper.instance()
private val retryPolicy = UploadDelayPolicy()

private val overridePowerSaving: Boolean
get() = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)

@Suppress("ReturnCount")
override suspend fun doWork(): Result {
return try {
Expand Down Expand Up @@ -184,7 +187,6 @@ class AutoUploadWorker(

@Suppress("ReturnCount")
private suspend fun canExitEarly(syncedFolderID: Long): Boolean {
val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)
if ((powerManagementService.isPowerSavingEnabled && !overridePowerSaving)) {
Log_OC.w(TAG, "⚡ Skipping: device is in power saving mode")
return true
Expand Down Expand Up @@ -448,7 +450,11 @@ class AutoUploadWorker(
upload.isWhileChargingOnly,
true,
FileDataStorageManager(user, context.contentResolver)
)
).apply {
if (overridePowerSaving) {
isIgnoringPowerSaveMode = true
}
}

private fun sendUploadFinishEvent(operation: UploadFileOperation, result: RemoteOperationResult<*>) {
fileUploadEventBroadcaster.sendUploadCompleted(
Expand Down
30 changes: 30 additions & 0 deletions app/src/main/java/com/nextcloud/ui/component/UploadWarningCard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@ import android.provider.Settings
import android.view.View
import androidx.core.net.toUri
import com.nextcloud.client.device.PowerManagementService
import com.nextcloud.client.jobs.BackgroundJobManager
import com.nextcloud.utils.extensions.setVisibleIf
import com.owncloud.android.R
import com.owncloud.android.databinding.UploadWarningCardBinding
import com.owncloud.android.datamodel.SyncedFolderProvider
import com.owncloud.android.utils.DisplayUtils
import com.owncloud.android.utils.FilesSyncHelper
import com.owncloud.android.utils.theme.ViewThemeUtils

class UploadWarningCard(
private val context: Context,
private val powerManagementService: PowerManagementService,
private val syncedFolderProvider: SyncedFolderProvider,
private val backgroundJobManager: BackgroundJobManager,
private val viewThemeUtils: ViewThemeUtils
) {
fun bind(binding: UploadWarningCardBinding) {
Expand All @@ -34,10 +41,15 @@ class UploadWarningCard(

if (isBatterySaver) {
viewThemeUtils.material.themeCardView(binding.batterySaverLayout)
viewThemeUtils.material.colorMaterialTextButton(binding.batterySaverButton)
viewThemeUtils.material.colorMaterialTextButton(binding.syncNowButton)
binding.batterySaverLayout.visibility = View.VISIBLE
binding.batterySaverButton.setOnClickListener {
openBatterySaverPage()
}
binding.syncNowButton.setOnClickListener {
startAutoUploadViaIgnoringBatteryOptimization(it)
}
} else {
binding.batterySaverLayout.visibility = View.GONE
}
Expand Down Expand Up @@ -76,6 +88,24 @@ class UploadWarningCard(
}
// endregion

private fun startAutoUploadViaIgnoringBatteryOptimization(view: View) {
val startedFolderCount = FilesSyncHelper.startAutoUploadForEnabledSyncedFolders(
syncedFolderProvider,
backgroundJobManager,
overridePowerSaving = true
)

backgroundJobManager.scheduleContentObserverJob(overridePowerSaving = true)

val message = if (startedFolderCount > 0) {
R.string.auto_upload_sync_now_started
} else {
R.string.auto_upload_sync_now_no_folder
}

DisplayUtils.showSnackMessage(view, message)
}

/**
* Opens page for OS's battery saver screen.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fun SyncedFolder.shouldSkipFile(
}

// If "upload existing files" is DISABLED, only upload files created after enabled time
if (!isExisting) {
if (!alsoUploadExistingFiles()) {
if (creationTime != null) {
if (creationTime < enabledTimestampMs) {
Log_OC.d(TAG, "Skipping pre-existing file (creation < enabled): ${file.absolutePath}")
Expand Down Expand Up @@ -149,7 +149,7 @@ fun SyncedFolder.getLog(): String {
📶 Wi-Fi only: $isWifiOnly
🔌 Charging only: $isChargingOnly

📤 Upload existing files: $isExisting
📤 Upload existing files: ${alsoUploadExistingFiles()}
⚙️ Upload action: $uploadAction
🧩 Name collision: $nameCollisionPolicy

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/owncloud/android/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ public void onCreate() {
}

Log_OC.d(TAG, "scheduleContentObserverJob, called");
backgroundJobManager.scheduleContentObserverJob();
backgroundJobManager.scheduleContentObserverJob(false);

initSyncOperations(this,
preferences,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public boolean isChargingOnly() {
*
* @return {@code true} if existing files should also be uploaded, {@code false} otherwise
*/
public boolean isExisting() {
public boolean alsoUploadExistingFiles() {
return this.existing;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class SyncedFolderProvider(
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_REMOTE_PATH, syncedFolder.remotePath)
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_WIFI_ONLY, syncedFolder.isWifiOnly)
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_CHARGING_ONLY, syncedFolder.isChargingOnly)
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_EXISTING, syncedFolder.isExisting)
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_EXISTING, syncedFolder.alsoUploadExistingFiles())
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED, syncedFolder.isEnabled)
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ENABLED_TIMESTAMP_MS, syncedFolder.enabledTimestampMs)
put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_BY_DATE, syncedFolder.isSubfolderByDate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public void onReceive(Context context, Intent intent) {
viewThemeUtils,
walledCheckCache);
Log_OC.d(TAG, "scheduleContentObserverJob, called");
backgroundJobManager.scheduleContentObserverJob();
backgroundJobManager.scheduleContentObserverJob(false);
MainApp.initContactsBackup(accountManager, backgroundJobManager);
} else {
Log_OC.d(TAG, "Getting wrong intent: " + intent.getAction());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public class UploadFileOperation extends SyncOperation {
private volatile int mCreatedBy;
private boolean mOnWifiOnly;
private boolean mWhileChargingOnly;
private boolean mIgnoringPowerSaveMode;
private volatile boolean mIgnoringPowerSaveMode;
private final boolean mDisableRetries;

private volatile boolean mWasRenamed;
Expand Down Expand Up @@ -293,6 +293,10 @@ public boolean isIgnoringPowerSaveMode() {
return mIgnoringPowerSaveMode;
}

public void setIgnoringPowerSaveMode(boolean ignoringPowerSaveMode) {
mIgnoringPowerSaveMode = ignoringPowerSaveMode;
}

public User getUser() {
return user;
}
Expand Down Expand Up @@ -1003,38 +1007,38 @@ private RemoteOperationResult releaseLocksAndUnlockE2EFolder(FileLock fileLock,
}
// endregion

private RemoteOperationResult checkConditions(File originalFile) {
RemoteOperationResult remoteOperationResult = null;
private RemoteOperationResult<Object> checkConditions(File originalFile) {
RemoteOperationResult<Object> remoteOperationResult = null;

// check that connectivity conditions are met and delays the upload otherwise
Connectivity connectivity = connectivityService.getConnectivity();
if (mOnWifiOnly && (!connectivity.isWifi() || connectivity.isMetered())) {
Log_OC.d(TAG, "Upload delayed until WiFi is available: " + getRemotePath());
remoteOperationResult = new RemoteOperationResult(ResultCode.DELAYED_FOR_WIFI);
remoteOperationResult = new RemoteOperationResult<>(ResultCode.DELAYED_FOR_WIFI);
}

// check if charging conditions are met and delays the upload otherwise
final BatteryStatus battery = powerManagementService.getBattery();
if (mWhileChargingOnly && !battery.isCharging()) {
Log_OC.d(TAG, "Upload delayed until the device is charging: " + getRemotePath());
remoteOperationResult = new RemoteOperationResult(ResultCode.DELAYED_FOR_CHARGING);
remoteOperationResult = new RemoteOperationResult<>(ResultCode.DELAYED_FOR_CHARGING);
}

// check that device is not in power save mode
if (!mIgnoringPowerSaveMode && powerManagementService.isPowerSavingEnabled()) {
Log_OC.d(TAG, "Upload delayed because device is in power save mode: " + getRemotePath());
remoteOperationResult = new RemoteOperationResult(ResultCode.DELAYED_IN_POWER_SAVE_MODE);
remoteOperationResult = 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 + " does not exist anymore");
remoteOperationResult = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND);
remoteOperationResult = new RemoteOperationResult<>(ResultCode.LOCAL_FILE_NOT_FOUND);
}

// check that internet is not behind walled garden
if (!connectivityService.getConnectivity().isConnected() || connectivityService.isInternetWalled()) {
remoteOperationResult = new RemoteOperationResult(ResultCode.NO_NETWORK_CONNECTION);
remoteOperationResult = new RemoteOperationResult<>(ResultCode.NO_NETWORK_CONNECTION);
}

return remoteOperationResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ class SyncedFoldersActivity :
super.onCreate(savedInstanceState)
binding = SyncedFoldersLayoutBinding.inflate(layoutInflater)
setContentView(binding.root)
uploadWarningCard = UploadWarningCard(this, powerManagementService, viewThemeUtils)
uploadWarningCard = UploadWarningCard(
this,
powerManagementService,
syncedFolderProvider,
backgroundJobManager,
viewThemeUtils
)
if (intent != null && intent.extras != null) {
val accountName = intent.extras!!.getString(NotificationWork.KEY_NOTIFICATION_ACCOUNT)
val optionalUser = user
Expand Down Expand Up @@ -404,7 +410,7 @@ class SyncedFoldersActivity :
syncedFolder.remotePath,
syncedFolder.isWifiOnly,
syncedFolder.isChargingOnly,
syncedFolder.isExisting,
syncedFolder.alsoUploadExistingFiles(),
syncedFolder.isSubfolderByDate,
syncedFolder.account,
syncedFolder.uploadAction,
Expand Down Expand Up @@ -436,7 +442,7 @@ class SyncedFoldersActivity :
syncedFolder.remotePath,
syncedFolder.isWifiOnly,
syncedFolder.isChargingOnly,
syncedFolder.isExisting,
syncedFolder.alsoUploadExistingFiles(),
syncedFolder.isSubfolderByDate,
syncedFolder.account,
syncedFolder.uploadAction,
Expand Down Expand Up @@ -851,7 +857,7 @@ class SyncedFoldersActivity :
item.remotePath = remotePath
item.isWifiOnly = wifiOnly
item.isChargingOnly = chargingOnly
item.isExisting = existing
item.setExisting(existing)
item.isSubfolderByDate = subfolderByDate
item.uploadAction = uploadAction
item.setNameCollisionPolicy(nameCollisionPolicy)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,13 @@ class UploadListActivity :
binding = UploadListLayoutBinding.inflate(layoutInflater)
val binding = binding!!
setContentView(binding.getRoot())
uploadWarningCard = UploadWarningCard(this, powerManagementService, viewThemeUtils)
uploadWarningCard = UploadWarningCard(
this,
powerManagementService,
syncedFolderProvider,
backgroundJobManager,
viewThemeUtils
)
swipeListRefreshLayout = binding.swipeContainingList

// this activity has no file really bound, it's for multiple accounts at the same time; should no inherit
Expand Down Expand Up @@ -174,6 +180,8 @@ class UploadListActivity :
accountManager,
powerManagementService
)

loadItems()
}

override fun onStart() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,10 @@ class UploadListAdapter(
fun loadUploadItemsFromDb(onCompleted: Runnable = {}) {
val optionalUser = activity.user
val optionalCapabilities = activity.capabilities
if (optionalUser.isEmpty || optionalCapabilities.isEmpty) return
if (optionalUser.isEmpty || optionalCapabilities.isEmpty) {
onCompleted.run()
return
}

val accountName = optionalUser.get().accountName
val capabilities = optionalCapabilities.get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public SyncedFolderParcelable(SyncedFolderDisplayItem syncedFolderDisplayItem, i
remotePath = syncedFolderDisplayItem.getRemotePath();
wifiOnly = syncedFolderDisplayItem.isWifiOnly();
chargingOnly = syncedFolderDisplayItem.isChargingOnly();
existing = syncedFolderDisplayItem.isExisting();
existing = syncedFolderDisplayItem.alsoUploadExistingFiles();
enabled = syncedFolderDisplayItem.isEnabled();
subfolderByDate = syncedFolderDisplayItem.isSubfolderByDate();
type = syncedFolderDisplayItem.getType();
Expand Down
11 changes: 5 additions & 6 deletions app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,12 @@ object FilesSyncHelper {
provider: SyncedFolderProvider,
manager: BackgroundJobManager,
overridePowerSaving: Boolean
) {
): Int {
Log_OC.d(TAG, "start auto upload worker for each enabled folder")

provider.syncedFolders.forEach {
if (it.isEnabled) {
manager.startAutoUpload(it, overridePowerSaving)
}
}
return provider.syncedFolders
.filter { it.isEnabled }
.onEach { manager.startAutoUpload(it, overridePowerSaving) }
.size
}
}
Loading
Loading