1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.app.job.IJobScheduler;
23 import android.app.job.IUserVisibleJobObserver;
24 import android.app.job.JobInfo;
25 import android.app.job.JobScheduler;
26 import android.app.job.JobSnapshot;
27 import android.app.job.JobWorkItem;
28 import android.content.Context;
29 import android.content.pm.ParceledListSlice;
30 import android.os.RemoteException;
31 import android.util.ArrayMap;
32 
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 
37 /**
38  * Concrete implementation of the JobScheduler interface
39  *
40  * Note android.app.job is the better package to put this class, but we can't move it there
41  * because that'd break robolectric. Grr.
42  *
43  * @hide
44  */
45 public class JobSchedulerImpl extends JobScheduler {
46     IJobScheduler mBinder;
47     private final Context mContext;
48     private final String mNamespace;
49 
JobSchedulerImpl(@onNull Context context, IJobScheduler binder)50     public JobSchedulerImpl(@NonNull Context context, IJobScheduler binder) {
51         this(context, binder, null);
52     }
53 
JobSchedulerImpl(@onNull Context context, IJobScheduler binder, @Nullable String namespace)54     private JobSchedulerImpl(@NonNull Context context, IJobScheduler binder,
55             @Nullable String namespace) {
56         mContext = context;
57         mBinder = binder;
58         mNamespace = namespace;
59     }
60 
JobSchedulerImpl(JobSchedulerImpl jsi, @Nullable String namespace)61     private JobSchedulerImpl(JobSchedulerImpl jsi, @Nullable String namespace) {
62         this(jsi.mContext, jsi.mBinder, namespace);
63     }
64 
65     @NonNull
66     @Override
forNamespace(@onNull String namespace)67     public JobScheduler forNamespace(@NonNull String namespace) {
68         namespace = sanitizeNamespace(namespace);
69         if (namespace == null) {
70             throw new NullPointerException("namespace cannot be null");
71         }
72         if (namespace.isEmpty()) {
73             throw new IllegalArgumentException("namespace cannot be empty");
74         }
75         return new JobSchedulerImpl(this, namespace);
76     }
77 
78     @Nullable
79     @Override
getNamespace()80     public String getNamespace() {
81         return mNamespace;
82     }
83 
84     @Override
schedule(JobInfo job)85     public int schedule(JobInfo job) {
86         try {
87             return mBinder.schedule(mNamespace, job);
88         } catch (RemoteException e) {
89             return JobScheduler.RESULT_FAILURE;
90         }
91     }
92 
93     @Override
enqueue(JobInfo job, JobWorkItem work)94     public int enqueue(JobInfo job, JobWorkItem work) {
95         try {
96             return mBinder.enqueue(mNamespace, job, work);
97         } catch (RemoteException e) {
98             return JobScheduler.RESULT_FAILURE;
99         }
100     }
101 
102     @Override
scheduleAsPackage(JobInfo job, String packageName, int userId, String tag)103     public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag) {
104         try {
105             return mBinder.scheduleAsPackage(mNamespace, job, packageName, userId, tag);
106         } catch (RemoteException e) {
107             return JobScheduler.RESULT_FAILURE;
108         }
109     }
110 
111     @Override
cancel(int jobId)112     public void cancel(int jobId) {
113         try {
114             mBinder.cancel(mNamespace, jobId);
115         } catch (RemoteException e) {}
116     }
117 
118     @Override
cancelAll()119     public void cancelAll() {
120         try {
121             mBinder.cancelAllInNamespace(mNamespace);
122         } catch (RemoteException e) {}
123     }
124 
125     @Override
cancelInAllNamespaces()126     public void cancelInAllNamespaces() {
127         try {
128             mBinder.cancelAll();
129         } catch (RemoteException e) {}
130     }
131 
132     @Override
getAllPendingJobs()133     public List<JobInfo> getAllPendingJobs() {
134         try {
135             return mBinder.getAllPendingJobsInNamespace(mNamespace).getList();
136         } catch (RemoteException e) {
137             return null;
138         }
139     }
140 
141     @Override
getPendingJobsInAllNamespaces()142     public Map<String, List<JobInfo>> getPendingJobsInAllNamespaces() {
143         try {
144             final Map<String, ParceledListSlice<JobInfo>> parceledList =
145                     mBinder.getAllPendingJobs();
146             final ArrayMap<String, List<JobInfo>> jobMap = new ArrayMap<>();
147             final Set<String> keys = parceledList.keySet();
148             for (String key : keys) {
149                 jobMap.put(key, parceledList.get(key).getList());
150             }
151             return jobMap;
152         } catch (RemoteException e) {
153             return null;
154         }
155     }
156 
157     @Override
getPendingJob(int jobId)158     public JobInfo getPendingJob(int jobId) {
159         try {
160             return mBinder.getPendingJob(mNamespace, jobId);
161         } catch (RemoteException e) {
162             return null;
163         }
164     }
165 
166     @Override
getPendingJobReason(int jobId)167     public int getPendingJobReason(int jobId) {
168         try {
169             return mBinder.getPendingJobReason(mNamespace, jobId);
170         } catch (RemoteException e) {
171             return PENDING_JOB_REASON_UNDEFINED;
172         }
173     }
174 
175     @Override
canRunUserInitiatedJobs()176     public boolean canRunUserInitiatedJobs() {
177         try {
178             return mBinder.canRunUserInitiatedJobs(mContext.getOpPackageName());
179         } catch (RemoteException e) {
180             return false;
181         }
182     }
183 
184     @Override
hasRunUserInitiatedJobsPermission(String packageName, int userId)185     public boolean hasRunUserInitiatedJobsPermission(String packageName, int userId) {
186         try {
187             return mBinder.hasRunUserInitiatedJobsPermission(packageName, userId);
188         } catch (RemoteException e) {
189             return false;
190         }
191     }
192 
193     @Override
getStartedJobs()194     public List<JobInfo> getStartedJobs() {
195         try {
196             return mBinder.getStartedJobs();
197         } catch (RemoteException e) {
198             return null;
199         }
200     }
201 
202     @Override
getAllJobSnapshots()203     public List<JobSnapshot> getAllJobSnapshots() {
204         try {
205             return mBinder.getAllJobSnapshots().getList();
206         } catch (RemoteException e) {
207             return null;
208         }
209     }
210 
211     @RequiresPermission(allOf = {
212             android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
213             android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
214     @Override
registerUserVisibleJobObserver(@onNull IUserVisibleJobObserver observer)215     public void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) {
216         try {
217             mBinder.registerUserVisibleJobObserver(observer);
218         } catch (RemoteException e) {
219         }
220     }
221 
222     @RequiresPermission(allOf = {
223             android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
224             android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
225     @Override
unregisterUserVisibleJobObserver(@onNull IUserVisibleJobObserver observer)226     public void unregisterUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) {
227         try {
228             mBinder.unregisterUserVisibleJobObserver(observer);
229         } catch (RemoteException e) {
230         }
231     }
232 
233     @RequiresPermission(allOf = {
234             android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
235             android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
236     @Override
notePendingUserRequestedAppStop(@onNull String packageName, int userId, @Nullable String debugReason)237     public void notePendingUserRequestedAppStop(@NonNull String packageName, int userId,
238             @Nullable String debugReason) {
239         try {
240             mBinder.notePendingUserRequestedAppStop(packageName, userId, debugReason);
241         } catch (RemoteException e) {
242         }
243     }
244 }
245