chromium/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.download.service;

import android.os.PersistableBundle;
import android.text.format.DateUtils;

import androidx.annotation.VisibleForTesting;

import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace;

import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.download.DownloadUtils;
import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
import org.chromium.components.background_task_scheduler.TaskIds;
import org.chromium.components.background_task_scheduler.TaskInfo;
import org.chromium.components.background_task_scheduler.TaskInfo.OneOffInfo;
import org.chromium.components.download.DownloadTaskType;

/**
 * A background task scheduler that schedules various types of jobs with the system with certain
 * conditions as requested by the download service.
 */
@JNINamespace("download::android")
public class DownloadTaskScheduler {
    public static final String EXTRA_BATTERY_REQUIRES_CHARGING = "extra_battery_requires_charging";
    public static final String EXTRA_OPTIMAL_BATTERY_PERCENTAGE =
            "extra_optimal_battery_percentage";
    public static final String EXTRA_TASK_TYPE = "extra_task_type";

    @VisibleForTesting
    @CalledByNative
    public static void scheduleTask(
            @DownloadTaskType int taskType,
            boolean requiresUnmeteredNetwork,
            boolean requiresCharging,
            int optimalBatteryPercentage,
            long windowStartTimeSeconds,
            long windowEndTimeSeconds) {
        PersistableBundle bundle = new PersistableBundle();
        bundle.putInt(EXTRA_TASK_TYPE, taskType);
        bundle.putInt(EXTRA_OPTIMAL_BATTERY_PERCENTAGE, optimalBatteryPercentage);
        bundle.putBoolean(EXTRA_BATTERY_REQUIRES_CHARGING, requiresCharging);

        int taskId = getTaskId(taskType);
        boolean isUserInitiatedJob = DownloadUtils.isUserInitiatedJob(taskId);

        BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler();
        OneOffInfo.Builder oneOffInfoBuilder = new OneOffInfo.Builder();
        if (!isUserInitiatedJob) {
            oneOffInfoBuilder.setWindowStartTimeMs(
                    DateUtils.SECOND_IN_MILLIS * windowStartTimeSeconds);
            oneOffInfoBuilder.setWindowEndTimeMs(DateUtils.SECOND_IN_MILLIS * windowEndTimeSeconds);
        }

        TaskInfo.Builder builder = TaskInfo.createTask(taskId, oneOffInfoBuilder.build());
        builder.setRequiredNetworkType(getRequiredNetworkType(taskType, requiresUnmeteredNetwork))
                .setRequiresCharging(requiresCharging)
                .setUserInitiated(isUserInitiatedJob)
                .setUpdateCurrent(true)
                .setIsPersisted(true)
                .setExtras(bundle);

        scheduler.schedule(ContextUtils.getApplicationContext(), builder.build());
    }

    @CalledByNative
    public static void cancelTask(@DownloadTaskType int taskType) {
        BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler();
        scheduler.cancel(ContextUtils.getApplicationContext(), getTaskId(taskType));
    }

    private static int getTaskId(@DownloadTaskType int taskType) {
        switch (taskType) {
            case DownloadTaskType.DOWNLOAD_TASK:
                return TaskIds.DOWNLOAD_SERVICE_JOB_ID;
            case DownloadTaskType.CLEANUP_TASK:
                return TaskIds.DOWNLOAD_CLEANUP_JOB_ID;
            case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK:
                return TaskIds.DOWNLOAD_AUTO_RESUMPTION_JOB_ID;
            case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_UNMETERED_TASK:
                return TaskIds.DOWNLOAD_AUTO_RESUMPTION_UNMETERED_JOB_ID;
            case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_ANY_NETWORK_TASK:
                return TaskIds.DOWNLOAD_AUTO_RESUMPTION_ANY_NETWORK_JOB_ID;
            case DownloadTaskType.DOWNLOAD_LATER_TASK:
                return TaskIds.DOWNLOAD_LATER_JOB_ID;
        }
        assert false : "Unknown download task type.";
        return -1;
    }

    private static int getRequiredNetworkType(
            @DownloadTaskType int taskType, boolean requiresUnmeteredNetwork) {
        switch (taskType) {
            case DownloadTaskType.CLEANUP_TASK:
                return TaskInfo.NetworkType.NONE;
            case DownloadTaskType.DOWNLOAD_TASK: // intentional fall-through
            case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK:
            case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_UNMETERED_TASK:
            case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_ANY_NETWORK_TASK:
                return requiresUnmeteredNetwork
                        ? TaskInfo.NetworkType.UNMETERED
                        : TaskInfo.NetworkType.ANY;
            case DownloadTaskType.DOWNLOAD_LATER_TASK:
                return TaskInfo.NetworkType.ANY;
        }
        assert false : "Unknown download task type.";
        return -1;
    }
}