Skip to content

Commit

Permalink
Merge pull request #12306 from nextcloud/add-info-for-background-worker
Browse files Browse the repository at this point in the history
Add info for background worker execution
  • Loading branch information
JonasMayerDev committed Dec 21, 2023
2 parents 251ef24 + e51cdf6 commit 14a6d65
Show file tree
Hide file tree
Showing 18 changed files with 298 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class BackgroundJobManagerTest {
clock = mock()
whenever(clock.currentTime).thenReturn(TIMESTAMP)
whenever(clock.currentDate).thenReturn(Date(TIMESTAMP))
backgroundJobManager = BackgroundJobManagerImpl(workManager, clock)
backgroundJobManager = BackgroundJobManagerImpl(workManager, clock, mock())
}

fun assertHasRequiredTags(tags: Set<String>, jobName: String, user: User? = null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import android.Manifest
import androidx.test.rule.GrantPermissionRule
import androidx.work.WorkManager
import com.nextcloud.client.core.ClockImpl
import com.nextcloud.client.preferences.AppPreferencesImpl
import com.nextcloud.test.RetryTestRule
import com.owncloud.android.AbstractIT
import com.owncloud.android.AbstractOnServerIT
Expand All @@ -43,7 +44,8 @@ import java.io.FileInputStream

class ContactsBackupIT : AbstractOnServerIT() {
val workmanager = WorkManager.getInstance(targetContext)
private val backgroundJobManager = BackgroundJobManagerImpl(workmanager, ClockImpl())
val preferences = AppPreferencesImpl.fromContext(targetContext)
private val backgroundJobManager = BackgroundJobManagerImpl(workmanager, ClockImpl(), preferences)

@get:Rule
val writeContactsRule = GrantPermissionRule.grant(Manifest.permission.WRITE_CONTACTS)
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@
import com.nextcloud.client.documentscan.DocumentScanActivity;
import com.nextcloud.client.editimage.EditImageActivity;
import com.nextcloud.client.etm.EtmActivity;
import com.nextcloud.client.etm.pages.EtmBackgroundJobsFragment;
import com.nextcloud.client.files.downloader.FileTransferService;
import com.nextcloud.client.jobs.BackgroundJobManagerImpl;
import com.nextcloud.client.jobs.NotificationWork;
import com.nextcloud.client.jobs.TestJob;
import com.nextcloud.client.logger.ui.LogsActivity;
import com.nextcloud.client.logger.ui.LogsViewModel;
import com.nextcloud.client.media.PlayerService;
Expand Down Expand Up @@ -478,4 +481,13 @@ abstract class ComponentsModule {

@ContributesAndroidInjector
abstract ImageDetailFragment imageDetailFragment();

@ContributesAndroidInjector
abstract EtmBackgroundJobsFragment etmBackgroundJobsFragment();

@ContributesAndroidInjector
abstract BackgroundJobManagerImpl backgroundJobManagerImpl();

@ContributesAndroidInjector
abstract TestJob testJob();
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/
package com.nextcloud.client.etm.pages

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
Expand All @@ -32,15 +33,23 @@ import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.nextcloud.client.di.Injectable
import com.nextcloud.client.etm.EtmBaseFragment
import com.nextcloud.client.jobs.BackgroundJobManagerImpl
import com.nextcloud.client.jobs.JobInfo
import com.nextcloud.client.preferences.AppPreferences
import com.owncloud.android.R
import java.text.SimpleDateFormat
import java.util.Locale
import javax.inject.Inject

class EtmBackgroundJobsFragment : EtmBaseFragment() {
class EtmBackgroundJobsFragment : EtmBaseFragment(), Injectable {

class Adapter(private val inflater: LayoutInflater) : RecyclerView.Adapter<Adapter.ViewHolder>() {
@Inject
lateinit var preferences: AppPreferences

class Adapter(private val inflater: LayoutInflater, private val preferences: AppPreferences) :
RecyclerView.Adapter<Adapter.ViewHolder>() {

class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val uuid = view.findViewById<TextView>(R.id.etm_background_job_uuid)
Expand All @@ -50,6 +59,10 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
val started = view.findViewById<TextView>(R.id.etm_background_job_started)
val progress = view.findViewById<TextView>(R.id.etm_background_job_progress)
private val progressRow = view.findViewById<View>(R.id.etm_background_job_progress_row)
val executionCount = view.findViewById<TextView>(R.id.etm_background_execution_count)
val executionLog = view.findViewById<TextView>(R.id.etm_background_execution_logs)
private val executionLogRow = view.findViewById<View>(R.id.etm_background_execution_logs_row)
val executionTimesRow = view.findViewById<View>(R.id.etm_background_execution_times_row)

var progressEnabled: Boolean = progressRow.visibility == View.VISIBLE
get() {
Expand All @@ -63,6 +76,19 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
View.GONE
}
}

var logsEnabled: Boolean = executionLogRow.visibility == View.VISIBLE
get() {
return executionLogRow.visibility == View.VISIBLE
}
set(value) {
field = value
executionLogRow.visibility = if (value) {
View.VISIBLE
} else {
View.GONE
}
}
}

private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:MM:ssZ", Locale.getDefault())
Expand All @@ -74,13 +100,20 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = inflater.inflate(R.layout.etm_background_job_list_item, parent, false)
return ViewHolder(view)
val viewHolder = ViewHolder(view)
viewHolder.logsEnabled = false
viewHolder.executionTimesRow.visibility = View.GONE
view.setOnClickListener {
viewHolder.logsEnabled = !viewHolder.logsEnabled
}
return viewHolder
}

override fun getItemCount(): Int {
return backgroundJobs.size
}

@SuppressLint("SetTextI18n")
override fun onBindViewHolder(vh: ViewHolder, position: Int) {
val info = backgroundJobs[position]
vh.uuid.text = info.id.toString()
Expand All @@ -94,6 +127,34 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
} else {
vh.progressEnabled = false
}

val logs = preferences.readLogEntry()
val logsForThisWorker =
logs.filter { BackgroundJobManagerImpl.parseTag(it.workerClass)?.second == info.workerClass }
if (logsForThisWorker.isNotEmpty()) {
vh.executionTimesRow.visibility = View.VISIBLE
vh.executionCount.text =
"${logsForThisWorker.filter { it.started != null }.size} " +
"(${logsForThisWorker.filter { it.finished != null }.size})"
var logText = "Worker Logs\n\n" +
"*** Does NOT differentiate between immediate or periodic kinds of Work! ***\n" +
"*** Times run in 48h: Times started (Times finished) ***\n"
logsForThisWorker.forEach {
logText += "----------------------\n"
logText += "Worker ${BackgroundJobManagerImpl.parseTag(it.workerClass)?.second}\n"
logText += if (it.started == null) {
"ENDED at\n${it.finished}\nWith result: ${it.result}\n"
} else {
"STARTED at\n${it.started}\n"
}
}
vh.executionLog.text = logText
} else {
vh.executionLog.text = "Worker Logs\n\n" +
"No Entries -> Maybe logging is not implemented for Worker or it has not run yet."
vh.executionCount.text = "0"
vh.executionTimesRow.visibility = View.GONE
}
}
}

Expand All @@ -107,7 +168,7 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_etm_background_jobs, container, false)
adapter = Adapter(inflater)
adapter = Adapter(inflater, preferences)
list = view.findViewById(R.id.etm_background_jobs_list)
list.layoutManager = LinearLayoutManager(context)
list.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
Expand All @@ -127,22 +188,27 @@ class EtmBackgroundJobsFragment : EtmBaseFragment() {
vm.cancelAllJobs()
true
}

R.id.etm_background_jobs_prune -> {
vm.pruneJobs()
true
}

R.id.etm_background_jobs_start_test -> {
vm.startTestJob(periodic = false)
true
}

R.id.etm_background_jobs_schedule_test -> {
vm.startTestJob(periodic = true)
true
}

R.id.etm_background_jobs_cancel_test -> {
vm.cancelTestJob()
true
}

else -> super.onOptionsItemSelected(item)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import javax.inject.Provider
*
* This class is doing too many things and should be split up into smaller factories.
*/
@Suppress("LongParameterList") // satisfied by DI
@Suppress("LongParameterList", "TooManyFunctions") // satisfied by DI
class BackgroundJobFactory @Inject constructor(
private val logger: Logger,
private val preferences: AppPreferences,
Expand Down Expand Up @@ -104,6 +104,7 @@ class BackgroundJobFactory @Inject constructor(
FilesUploadWorker::class -> createFilesUploadWorker(context, workerParameters)
GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters)
HealthStatusWork::class -> createHealthStatusWork(context, workerParameters)
TestJob::class -> createTestJob(context, workerParameters)
else -> null // caller falls back to default factory
}
}
Expand Down Expand Up @@ -183,7 +184,8 @@ class BackgroundJobFactory @Inject constructor(
uploadsStorageManager = uploadsStorageManager,
connectivityService = connectivityService,
powerManagementService = powerManagementService,
syncedFolderProvider = syncedFolderProvider
syncedFolderProvider = syncedFolderProvider,
backgroundJobManager = backgroundJobManager.get()
)
}

Expand Down Expand Up @@ -245,6 +247,7 @@ class BackgroundJobFactory @Inject constructor(
accountManager,
viewThemeUtils.get(),
localBroadcastManager.get(),
backgroundJobManager.get(),
context,
params
)
Expand All @@ -267,7 +270,16 @@ class BackgroundJobFactory @Inject constructor(
context,
params,
accountManager,
arbitraryDataProvider
arbitraryDataProvider,
backgroundJobManager.get()
)
}

private fun createTestJob(context: Context, params: WorkerParameters): TestJob {
return TestJob(
context,
params,
backgroundJobManager.get()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package com.nextcloud.client.jobs

import androidx.lifecycle.LiveData
import androidx.work.ListenableWorker
import com.nextcloud.client.account.User
import com.owncloud.android.datamodel.OCFile

Expand All @@ -35,6 +36,10 @@ interface BackgroundJobManager {
*/
val jobs: LiveData<List<JobInfo>>

fun logStartOfWorker(workerName: String?)

fun logEndOfWorker(workerName: String?, result: ListenableWorker.Result)

/**
* Start content observer job that monitors changes in media folders
* and launches synchronization when needed.
Expand Down
Loading

0 comments on commit 14a6d65

Please sign in to comment.