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