1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.chrome.browser.download.service;
6 
7 import android.os.Bundle;
8 import android.text.format.DateUtils;
9 
10 import org.chromium.base.ContextUtils;
11 import org.chromium.base.TimeUtils;
12 import org.chromium.base.annotations.CalledByNative;
13 import org.chromium.base.annotations.JNINamespace;
14 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
15 import org.chromium.chrome.browser.flags.ChromeFeatureList;
16 import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
17 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
18 import org.chromium.components.background_task_scheduler.TaskIds;
19 import org.chromium.components.background_task_scheduler.TaskInfo;
20 import org.chromium.components.download.DownloadTaskType;
21 
22 /**
23  * A background task scheduler that schedules various types of jobs with the system with certain
24  * conditions as requested by the download service.
25  */
26 @JNINamespace("download::android")
27 public class DownloadTaskScheduler {
28     public static final String EXTRA_BATTERY_REQUIRES_CHARGING = "extra_battery_requires_charging";
29     public static final String EXTRA_OPTIMAL_BATTERY_PERCENTAGE =
30             "extra_optimal_battery_percentage";
31     public static final String EXTRA_TASK_TYPE = "extra_task_type";
32 
33     @CalledByNative
scheduleTask(@ownloadTaskType int taskType, boolean requiresUnmeteredNetwork, boolean requiresCharging, int optimalBatteryPercentage, long windowStartTimeSeconds, long windowEndTimeSeconds)34     private static void scheduleTask(@DownloadTaskType int taskType,
35             boolean requiresUnmeteredNetwork, boolean requiresCharging,
36             int optimalBatteryPercentage, long windowStartTimeSeconds, long windowEndTimeSeconds) {
37         Bundle bundle = new Bundle();
38         bundle.putInt(EXTRA_TASK_TYPE, taskType);
39         bundle.putInt(EXTRA_OPTIMAL_BATTERY_PERCENTAGE, optimalBatteryPercentage);
40         bundle.putBoolean(EXTRA_BATTERY_REQUIRES_CHARGING, requiresCharging);
41 
42         BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler();
43         TaskInfo taskInfo = TaskInfo.createOneOffTask(getTaskId(taskType),
44                                             DateUtils.SECOND_IN_MILLIS * windowStartTimeSeconds,
45                                             DateUtils.SECOND_IN_MILLIS * windowEndTimeSeconds)
46                                     .setRequiredNetworkType(getRequiredNetworkType(
47                                             taskType, requiresUnmeteredNetwork))
48                                     .setRequiresCharging(requiresCharging)
49                                     .setUpdateCurrent(true)
50                                     .setIsPersisted(true)
51                                     .setExtras(bundle)
52                                     .build();
53         scheduler.schedule(ContextUtils.getApplicationContext(), taskInfo);
54     }
55 
56     @CalledByNative
cancelTask(@ownloadTaskType int taskType)57     private static void cancelTask(@DownloadTaskType int taskType) {
58         BackgroundTaskScheduler scheduler = BackgroundTaskSchedulerFactory.getScheduler();
59         scheduler.cancel(ContextUtils.getApplicationContext(), getTaskId(taskType));
60     }
61 
62     /**
63      * Invoked when the system sends a reschedule() call, which might happen in case of OS or play
64      * services upgrade etc. This will schedule the tasks in future with least restrictive criteria.
65      */
rescheduleAllTasks()66     public static void rescheduleAllTasks() {
67         scheduleTask(DownloadTaskType.DOWNLOAD_TASK, false, false, 0,
68                 TimeUtils.SECONDS_PER_MINUTE * 5, TimeUtils.SECONDS_PER_MINUTE * 10);
69         scheduleTask(DownloadTaskType.CLEANUP_TASK, false, false, 0,
70                 TimeUtils.SECONDS_PER_HOUR * 12, TimeUtils.SECONDS_PER_HOUR * 24);
71         if (CachedFeatureFlags.isEnabled(ChromeFeatureList.DOWNLOADS_AUTO_RESUMPTION_NATIVE)) {
72             scheduleTask(DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK, false, false, 0,
73                     TimeUtils.SECONDS_PER_MINUTE * 5, TimeUtils.SECONDS_PER_DAY);
74         }
75     }
76 
getTaskId(@ownloadTaskType int taskType)77     private static int getTaskId(@DownloadTaskType int taskType) {
78         switch (taskType) {
79             case DownloadTaskType.DOWNLOAD_TASK:
80                 return TaskIds.DOWNLOAD_SERVICE_JOB_ID;
81             case DownloadTaskType.CLEANUP_TASK:
82                 return TaskIds.DOWNLOAD_CLEANUP_JOB_ID;
83             case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK:
84                 return TaskIds.DOWNLOAD_AUTO_RESUMPTION_JOB_ID;
85             case DownloadTaskType.DOWNLOAD_LATER_TASK:
86                 return TaskIds.DOWNLOAD_LATER_JOB_ID;
87         }
88         assert false : "Unknown download task type.";
89         return -1;
90     }
91 
getRequiredNetworkType( @ownloadTaskType int taskType, boolean requiresUnmeteredNetwork)92     private static int getRequiredNetworkType(
93             @DownloadTaskType int taskType, boolean requiresUnmeteredNetwork) {
94         switch (taskType) {
95             case DownloadTaskType.CLEANUP_TASK:
96                 return TaskInfo.NetworkType.NONE;
97             case DownloadTaskType.DOWNLOAD_TASK: // intentional fall-through
98             case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK:
99                 return requiresUnmeteredNetwork ? TaskInfo.NetworkType.UNMETERED
100                                                 : TaskInfo.NetworkType.ANY;
101             case DownloadTaskType.DOWNLOAD_LATER_TASK:
102                 return TaskInfo.NetworkType.ANY;
103         }
104         assert false : "Unknown download task type.";
105         return -1;
106     }
107 }
108