Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d5fd4a9 authored by Austin Tankiang's avatar Austin Tankiang
Browse files

Add cancel functionality to job progress items

This also dismisses items when they are cancelled.

Bug: 400352714
Test: atest -c 'DocumentsUIGoogleTests:com.android.documentsui.JobPanelUiTest'
Flag: com.android.documentsui.flags.visual_signals_ro
Change-Id: I218b6cedebcbd2205e514e7d5a1acb656cc7751f
parent 8d53b1e9
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.android.documentsui.base.Menus
import com.android.documentsui.services.FileOperationService
import com.android.documentsui.services.FileOperationService.EXTRA_PROGRESS
import com.android.documentsui.services.FileOperations
import com.android.documentsui.services.Job
import com.android.documentsui.services.JobProgress
import com.android.documentsui.util.FormatUtils
@@ -129,6 +130,7 @@ class JobPanelController(private val activityContext: Context) : BroadcastReceiv
            cancelButton.isVisible = expanded && !jobProgress.isFinal
            showInFolderButton.isVisible = expanded && jobProgress.isFinal
            dismissButton.isVisible = expanded && jobProgress.isFinal
            cancelButton.setOnClickListener { FileOperations.cancel(context, jobProgress.id) }
            dismissButton.setOnClickListener { controller.dismissProgress(jobProgress.id) }
        }

@@ -367,8 +369,12 @@ class JobPanelController(private val activityContext: Context) : BroadcastReceiv

        for (jobProgress in progresses) {
            Log.d(TAG, "Received $jobProgress")
            currentJobs.merge(jobProgress.id, ProgressViewModel(jobProgress)) {
                old, new -> ProgressViewModel(new.jobProgress, old.expanded)
            if (jobProgress.state == Job.STATE_CANCELED) {
                currentJobs.remove(jobProgress.id)
            } else {
                currentJobs.merge(jobProgress.id, ProgressViewModel(jobProgress)) { old, new ->
                    ProgressViewModel(new.jobProgress, old.expanded)
                }
            }
        }
        for ((jobProgress, _) in currentJobs.values) {
+11 −7
Original line number Diff line number Diff line
@@ -17,18 +17,18 @@
package com.android.documentsui.services;

import static android.os.SystemClock.elapsedRealtime;

import static com.android.documentsui.base.SharedMinimal.DEBUG;
import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;

import androidx.annotation.IntDef;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.VisibleForTesting;
import android.util.Log;

import androidx.annotation.IntDef;

import com.android.documentsui.services.FileOperationService.OpType;

import java.lang.annotation.Retention;
@@ -74,17 +74,21 @@ public final class FileOperations {
        return newJobId;
    }

    @VisibleForTesting
    public static void cancel(Activity activity, String jobId) {
    /**
     * Tries to cancel a given operation by its job id.
     * @param context
     * @param jobId The job to cancel.
     */
    public static void cancel(Context context, String jobId) {
        if (DEBUG) {
            Log.d(TAG, "Attempting to canceling operation: " + jobId);
        }

        Intent intent = new Intent(activity, FileOperationService.class);
        Intent intent = new Intent(context, FileOperationService.class);
        intent.putExtra(EXTRA_CANCEL, true);
        intent.putExtra(EXTRA_JOB_ID, jobId);

        activity.startService(intent);
        context.startService(intent);
    }

    /**
+59 −8
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.view.View
import android.widget.ProgressBar
import androidx.test.espresso.Espresso
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
@@ -84,6 +85,13 @@ class JobPanelUiTest : ActivityTestJunit4<FilesActivity>() {
        context.sendBroadcast(intent)
    }

    private fun openPanel() {
        onView(withId(R.id.option_menu_job_progress))
            .check(matches(isDisplayed()))
            .perform(click())
        onView(withId(R.id.job_progress_panel_title)).check(matches(isDisplayed()))
    }

    @Test
    fun testInProgressItems() {
        onView(withId(R.id.option_menu_job_progress)).check(doesNotExist())
@@ -101,10 +109,7 @@ class JobPanelUiTest : ActivityTestJunit4<FilesActivity>() {
        )
        sendProgress(arrayListOf(progress.toJobProgress()))

        onView(withId(R.id.option_menu_job_progress))
            .check(matches(isDisplayed()))
            .perform(click())
        onView(withId(R.id.job_progress_panel_title)).check(matches(isDisplayed()))
        openPanel()

        val expectedPrimaryStatus = "4 B of 10 B"
        val expectedSecondaryStatus = "10 seconds left"
@@ -144,10 +149,7 @@ class JobPanelUiTest : ActivityTestJunit4<FilesActivity>() {
        )
        sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress()))

        onView(withId(R.id.option_menu_job_progress))
            .check(matches(isDisplayed()))
            .perform(click())
        onView(withId(R.id.job_progress_panel_title)).check(matches(isDisplayed()))
        openPanel()

        onView(withChild(withText(progress1.msg)))
            .check(selectedDescendantsMatch(
@@ -185,4 +187,53 @@ class JobPanelUiTest : ActivityTestJunit4<FilesActivity>() {
        onView(withId(R.id.option_menu_job_progress)).check(doesNotExist())
        onView(withId(R.id.job_progress_panel_title)).check(doesNotExist())
    }

    @Test
    fun testJobCanceled() {
        val progress1 = MutableJobProgress(
            id = "jobId1",
            operationType = FileOperationService.OPERATION_COPY,
            state = Job.STATE_SET_UP,
            msg = "Job1",
            hasFailures = false,
            currentBytes = 10,
            requiredBytes = 20,
            msRemaining = 1000,
        )
        val progress2 = MutableJobProgress(
            id = "jobId2",
            operationType = FileOperationService.OPERATION_EXTRACT,
            state = Job.STATE_CREATED,
            msg = "Job2",
            hasFailures = false,
        )
        sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress()))

        // Overall progress should be 25%.
        onView(withId(R.id.option_menu_job_progress)).check(matches(withProgress(25)))

        openPanel()

        // Check both items are displayed.
        onView(withText(progress1.msg)).check(matches(isDisplayed()))
        onView(withText(progress2.msg)).check(matches(isDisplayed()))

        // Cancel the first job. Only the second item should be displayed.
        progress1.state = Job.STATE_CANCELED
        sendProgress(arrayListOf(progress1.toJobProgress(), progress2.toJobProgress()))
        onView(withText(progress1.msg)).check(doesNotExist())
        onView(withText(progress2.msg)).check(matches(isDisplayed()))

        // Overall progress should be 0% as the first job doesn't count. We need to close the popup
        // panel first in order to check the menu item behind.
        Espresso.pressBack()
        onView(withId(R.id.option_menu_job_progress)).check(matches(withProgress(0)))
        openPanel()

        // Cancel the second job. The panel should disappear.
        progress2.state = Job.STATE_CANCELED
        sendProgress(arrayListOf(progress2.toJobProgress()))
        onView(withId(R.id.option_menu_job_progress)).check(doesNotExist())
        onView(withId(R.id.job_progress_panel_title)).check(doesNotExist())
    }
}