Loading src/com/android/documentsui/JobPanelViewModel.kt +6 −1 Original line number Diff line number Diff line Loading @@ -78,11 +78,15 @@ class JobPanelViewModel : ViewModel() { } /** * Updates the list of progresses managed by this class. * Updates the list of progresses managed by this class. This function will add and update all * given items, while removing any queued/in progress items not in [progresses]. Completed items * are kept. */ fun updateProgress(progresses: List<JobProgress>) { val seen = hashSetOf<String>() for (jobProgress in progresses) { if (DEBUG) Log.d(TAG, "Received $jobProgress") seen.add(jobProgress.id) if (jobProgress.state == Job.STATE_CANCELED) { _currentJobs.remove(jobProgress.id) } else { Loading @@ -91,6 +95,7 @@ class JobPanelViewModel : ViewModel() { } } } _currentJobs.entries.removeAll { (id, model) -> !model.jobProgress.isFinal && id !in seen } } /** Loading tests/unit/com/android/documentsui/JobPanelViewModelTest.kt 0 → 100644 +181 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui import android.platform.test.annotations.RequiresFlagsEnabled import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.documentsui.JobPanelViewModel.ProgressViewModel import com.android.documentsui.flags.Flags.FLAG_USE_MATERIAL3 import com.android.documentsui.flags.Flags.FLAG_VISUAL_SIGNALS_RO import com.android.documentsui.rules.CheckAndForceMaterial3Flag import com.android.documentsui.services.FileOperationService import com.android.documentsui.services.Job import com.android.documentsui.testing.MutableJobProgress import junit.framework.Assert.assertEquals import junit.framework.Assert.assertTrue import kotlin.collections.emptyList import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith private fun List<MutableJobProgress>.toJobProgressList() = map { item -> item.toJobProgress() } private fun List<MutableJobProgress>.withExpandStates(vararg expandStates: Boolean): List<ProgressViewModel> = toJobProgressList().zip(expandStates.asList(), ::ProgressViewModel) @SmallTest @RequiresFlagsEnabled(FLAG_USE_MATERIAL3, FLAG_VISUAL_SIGNALS_RO) @RunWith(AndroidJUnit4::class) class JobPanelViewModelTest { @get:Rule val checkFlags = CheckAndForceMaterial3Flag() @Test fun testListModifications() { val viewModel = JobPanelViewModel() val progress1 = MutableJobProgress( id = "Job1", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job1", hasFailures = false, ) val progress2 = MutableJobProgress( id = "Job2", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job2", hasFailures = false, ) viewModel.updateProgress(listOf(progress1, progress2).toJobProgressList()) assertEquals( listOf(progress1, progress2) .withExpandStates(false, false), ArrayList(viewModel.currentJobs.values) ) val progress3 = MutableJobProgress( id = "Job3", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_STARTED, msg = "Job3", hasFailures = false, ) val progress4 = MutableJobProgress( id = "Job4", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_SET_UP, msg = "Job4", hasFailures = false, currentBytes = 50, requiredBytes = 100, msRemaining = 4000 ) viewModel.toggleExpanded("Job2") viewModel .updateProgress(listOf(progress1, progress2, progress3, progress4).toJobProgressList()) assertEquals( listOf(progress1, progress2, progress3, progress4) .withExpandStates(false, true, false, false), ArrayList(viewModel.currentJobs.values) ) progress1.state = Job.STATE_COMPLETED progress2.state = Job.STATE_COMPLETED progress2.hasFailures = true viewModel.updateProgress(listOf(progress1, progress2, progress4).toJobProgressList()) assertEquals( listOf(progress1, progress2, progress4) .withExpandStates(false, true, false), ArrayList(viewModel.currentJobs.values) ) progress4.state = Job.STATE_CANCELED viewModel.updateProgress(listOf(progress4).toJobProgressList()) // Progresses 1 and 2 should be kept as they are in the completed state. assertEquals( listOf(progress1, progress2) .withExpandStates(false, true), ArrayList(viewModel.currentJobs.values) ) viewModel.updateProgress(emptyList()) assertEquals( listOf(progress1, progress2) .withExpandStates(false, true), ArrayList(viewModel.currentJobs.values) ) viewModel.dismissProgress("Job1") assertEquals( listOf(progress2).withExpandStates(true), ArrayList(viewModel.currentJobs.values) ) } @Test fun testDismissNonExistentItem() { val viewModel = JobPanelViewModel() viewModel.dismissProgress("Job1") assertTrue(viewModel.currentJobs.isEmpty()) val progress1 = MutableJobProgress( id = "Job1", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job1", hasFailures = false, ) viewModel.updateProgress(listOf(progress1).toJobProgressList()) viewModel.dismissProgress("Job2") assertEquals( listOf(progress1).withExpandStates(false), ArrayList(viewModel.currentJobs.values) ) } @Test fun testExpandNonExistentItem() { val viewModel = JobPanelViewModel() viewModel.toggleExpanded("Job1") assertTrue(viewModel.currentJobs.isEmpty()) val progress1 = MutableJobProgress( id = "Job1", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job1", hasFailures = false, ) viewModel.updateProgress(listOf(progress1).toJobProgressList()) viewModel.toggleExpanded("Job2") assertEquals( listOf(progress1).withExpandStates(false), ArrayList(viewModel.currentJobs.values) ) } } Loading
src/com/android/documentsui/JobPanelViewModel.kt +6 −1 Original line number Diff line number Diff line Loading @@ -78,11 +78,15 @@ class JobPanelViewModel : ViewModel() { } /** * Updates the list of progresses managed by this class. * Updates the list of progresses managed by this class. This function will add and update all * given items, while removing any queued/in progress items not in [progresses]. Completed items * are kept. */ fun updateProgress(progresses: List<JobProgress>) { val seen = hashSetOf<String>() for (jobProgress in progresses) { if (DEBUG) Log.d(TAG, "Received $jobProgress") seen.add(jobProgress.id) if (jobProgress.state == Job.STATE_CANCELED) { _currentJobs.remove(jobProgress.id) } else { Loading @@ -91,6 +95,7 @@ class JobPanelViewModel : ViewModel() { } } } _currentJobs.entries.removeAll { (id, model) -> !model.jobProgress.isFinal && id !in seen } } /** Loading
tests/unit/com/android/documentsui/JobPanelViewModelTest.kt 0 → 100644 +181 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui import android.platform.test.annotations.RequiresFlagsEnabled import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.documentsui.JobPanelViewModel.ProgressViewModel import com.android.documentsui.flags.Flags.FLAG_USE_MATERIAL3 import com.android.documentsui.flags.Flags.FLAG_VISUAL_SIGNALS_RO import com.android.documentsui.rules.CheckAndForceMaterial3Flag import com.android.documentsui.services.FileOperationService import com.android.documentsui.services.Job import com.android.documentsui.testing.MutableJobProgress import junit.framework.Assert.assertEquals import junit.framework.Assert.assertTrue import kotlin.collections.emptyList import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith private fun List<MutableJobProgress>.toJobProgressList() = map { item -> item.toJobProgress() } private fun List<MutableJobProgress>.withExpandStates(vararg expandStates: Boolean): List<ProgressViewModel> = toJobProgressList().zip(expandStates.asList(), ::ProgressViewModel) @SmallTest @RequiresFlagsEnabled(FLAG_USE_MATERIAL3, FLAG_VISUAL_SIGNALS_RO) @RunWith(AndroidJUnit4::class) class JobPanelViewModelTest { @get:Rule val checkFlags = CheckAndForceMaterial3Flag() @Test fun testListModifications() { val viewModel = JobPanelViewModel() val progress1 = MutableJobProgress( id = "Job1", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job1", hasFailures = false, ) val progress2 = MutableJobProgress( id = "Job2", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job2", hasFailures = false, ) viewModel.updateProgress(listOf(progress1, progress2).toJobProgressList()) assertEquals( listOf(progress1, progress2) .withExpandStates(false, false), ArrayList(viewModel.currentJobs.values) ) val progress3 = MutableJobProgress( id = "Job3", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_STARTED, msg = "Job3", hasFailures = false, ) val progress4 = MutableJobProgress( id = "Job4", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_SET_UP, msg = "Job4", hasFailures = false, currentBytes = 50, requiredBytes = 100, msRemaining = 4000 ) viewModel.toggleExpanded("Job2") viewModel .updateProgress(listOf(progress1, progress2, progress3, progress4).toJobProgressList()) assertEquals( listOf(progress1, progress2, progress3, progress4) .withExpandStates(false, true, false, false), ArrayList(viewModel.currentJobs.values) ) progress1.state = Job.STATE_COMPLETED progress2.state = Job.STATE_COMPLETED progress2.hasFailures = true viewModel.updateProgress(listOf(progress1, progress2, progress4).toJobProgressList()) assertEquals( listOf(progress1, progress2, progress4) .withExpandStates(false, true, false), ArrayList(viewModel.currentJobs.values) ) progress4.state = Job.STATE_CANCELED viewModel.updateProgress(listOf(progress4).toJobProgressList()) // Progresses 1 and 2 should be kept as they are in the completed state. assertEquals( listOf(progress1, progress2) .withExpandStates(false, true), ArrayList(viewModel.currentJobs.values) ) viewModel.updateProgress(emptyList()) assertEquals( listOf(progress1, progress2) .withExpandStates(false, true), ArrayList(viewModel.currentJobs.values) ) viewModel.dismissProgress("Job1") assertEquals( listOf(progress2).withExpandStates(true), ArrayList(viewModel.currentJobs.values) ) } @Test fun testDismissNonExistentItem() { val viewModel = JobPanelViewModel() viewModel.dismissProgress("Job1") assertTrue(viewModel.currentJobs.isEmpty()) val progress1 = MutableJobProgress( id = "Job1", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job1", hasFailures = false, ) viewModel.updateProgress(listOf(progress1).toJobProgressList()) viewModel.dismissProgress("Job2") assertEquals( listOf(progress1).withExpandStates(false), ArrayList(viewModel.currentJobs.values) ) } @Test fun testExpandNonExistentItem() { val viewModel = JobPanelViewModel() viewModel.toggleExpanded("Job1") assertTrue(viewModel.currentJobs.isEmpty()) val progress1 = MutableJobProgress( id = "Job1", operationType = FileOperationService.OPERATION_COPY, state = Job.STATE_CREATED, msg = "Job1", hasFailures = false, ) viewModel.updateProgress(listOf(progress1).toJobProgressList()) viewModel.toggleExpanded("Job2") assertEquals( listOf(progress1).withExpandStates(false), ArrayList(viewModel.currentJobs.values) ) } }