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.app.job.PendingJobReasonsInfo; 29 import android.content.Context; 30 import android.content.pm.ParceledListSlice; 31 import android.os.RemoteException; 32 import android.util.ArrayMap; 33 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Set; 38 39 /** 40 * Concrete implementation of the JobScheduler interface 41 * 42 * Note android.app.job is the better package to put this class, but we can't move it there 43 * because that'd break robolectric. Grr. 44 * 45 * @hide 46 */ 47 public class JobSchedulerImpl extends JobScheduler { 48 IJobScheduler mBinder; 49 private final Context mContext; 50 private final String mNamespace; 51 JobSchedulerImpl(@onNull Context context, IJobScheduler binder)52 public JobSchedulerImpl(@NonNull Context context, IJobScheduler binder) { 53 this(context, binder, null); 54 } 55 JobSchedulerImpl(@onNull Context context, IJobScheduler binder, @Nullable String namespace)56 private JobSchedulerImpl(@NonNull Context context, IJobScheduler binder, 57 @Nullable String namespace) { 58 mContext = context; 59 mBinder = binder; 60 mNamespace = namespace; 61 } 62 JobSchedulerImpl(JobSchedulerImpl jsi, @Nullable String namespace)63 private JobSchedulerImpl(JobSchedulerImpl jsi, @Nullable String namespace) { 64 this(jsi.mContext, jsi.mBinder, namespace); 65 } 66 67 @NonNull 68 @Override forNamespace(@onNull String namespace)69 public JobScheduler forNamespace(@NonNull String namespace) { 70 namespace = sanitizeNamespace(namespace); 71 if (namespace == null) { 72 throw new NullPointerException("namespace cannot be null"); 73 } 74 if (namespace.isEmpty()) { 75 throw new IllegalArgumentException("namespace cannot be empty"); 76 } 77 return new JobSchedulerImpl(this, namespace); 78 } 79 80 @Nullable 81 @Override getNamespace()82 public String getNamespace() { 83 return mNamespace; 84 } 85 86 @Override schedule(JobInfo job)87 public int schedule(JobInfo job) { 88 try { 89 return mBinder.schedule(mNamespace, job); 90 } catch (RemoteException e) { 91 return JobScheduler.RESULT_FAILURE; 92 } 93 } 94 95 @Override enqueue(JobInfo job, JobWorkItem work)96 public int enqueue(JobInfo job, JobWorkItem work) { 97 try { 98 return mBinder.enqueue(mNamespace, job, work); 99 } catch (RemoteException e) { 100 return JobScheduler.RESULT_FAILURE; 101 } 102 } 103 104 @Override scheduleAsPackage(JobInfo job, String packageName, int userId, String tag)105 public int scheduleAsPackage(JobInfo job, String packageName, int userId, String tag) { 106 try { 107 return mBinder.scheduleAsPackage(mNamespace, job, packageName, userId, tag); 108 } catch (RemoteException e) { 109 return JobScheduler.RESULT_FAILURE; 110 } 111 } 112 113 @Override cancel(int jobId)114 public void cancel(int jobId) { 115 try { 116 mBinder.cancel(mNamespace, jobId); 117 } catch (RemoteException e) {} 118 } 119 120 @Override cancelAll()121 public void cancelAll() { 122 try { 123 mBinder.cancelAllInNamespace(mNamespace); 124 } catch (RemoteException e) {} 125 } 126 127 @Override cancelInAllNamespaces()128 public void cancelInAllNamespaces() { 129 try { 130 mBinder.cancelAll(); 131 } catch (RemoteException e) {} 132 } 133 134 @Override getAllPendingJobs()135 public List<JobInfo> getAllPendingJobs() { 136 try { 137 return mBinder.getAllPendingJobsInNamespace(mNamespace).getList(); 138 } catch (RemoteException e) { 139 return null; 140 } 141 } 142 143 @Override getPendingJobsInAllNamespaces()144 public Map<String, List<JobInfo>> getPendingJobsInAllNamespaces() { 145 try { 146 final Map<String, ParceledListSlice<JobInfo>> parceledList = 147 mBinder.getAllPendingJobs(); 148 final ArrayMap<String, List<JobInfo>> jobMap = new ArrayMap<>(); 149 final Set<String> keys = parceledList.keySet(); 150 for (String key : keys) { 151 jobMap.put(key, parceledList.get(key).getList()); 152 } 153 return jobMap; 154 } catch (RemoteException e) { 155 return null; 156 } 157 } 158 159 @Override getPendingJob(int jobId)160 public JobInfo getPendingJob(int jobId) { 161 try { 162 return mBinder.getPendingJob(mNamespace, jobId); 163 } catch (RemoteException e) { 164 return null; 165 } 166 } 167 168 @Override getPendingJobReason(int jobId)169 public int getPendingJobReason(int jobId) { 170 try { 171 return mBinder.getPendingJobReason(mNamespace, jobId); 172 } catch (RemoteException e) { 173 return PENDING_JOB_REASON_UNDEFINED; 174 } 175 } 176 177 @Override 178 @NonNull getPendingJobReasons(int jobId)179 public int[] getPendingJobReasons(int jobId) { 180 try { 181 return mBinder.getPendingJobReasons(mNamespace, jobId); 182 } catch (RemoteException e) { 183 return new int[] { PENDING_JOB_REASON_UNDEFINED }; 184 } 185 } 186 187 @Override 188 @NonNull getPendingJobReasonsHistory(int jobId)189 public List<PendingJobReasonsInfo> getPendingJobReasonsHistory(int jobId) { 190 try { 191 return mBinder.getPendingJobReasonsHistory(mNamespace, jobId); 192 } catch (RemoteException e) { 193 return Collections.EMPTY_LIST; 194 } 195 } 196 197 @Override canRunUserInitiatedJobs()198 public boolean canRunUserInitiatedJobs() { 199 try { 200 return mBinder.canRunUserInitiatedJobs(mContext.getOpPackageName()); 201 } catch (RemoteException e) { 202 return false; 203 } 204 } 205 206 @Override hasRunUserInitiatedJobsPermission(String packageName, int userId)207 public boolean hasRunUserInitiatedJobsPermission(String packageName, int userId) { 208 try { 209 return mBinder.hasRunUserInitiatedJobsPermission(packageName, userId); 210 } catch (RemoteException e) { 211 return false; 212 } 213 } 214 215 @Override getStartedJobs()216 public List<JobInfo> getStartedJobs() { 217 try { 218 return mBinder.getStartedJobs(); 219 } catch (RemoteException e) { 220 return null; 221 } 222 } 223 224 @Override getAllJobSnapshots()225 public List<JobSnapshot> getAllJobSnapshots() { 226 try { 227 return mBinder.getAllJobSnapshots().getList(); 228 } catch (RemoteException e) { 229 return null; 230 } 231 } 232 233 @RequiresPermission(allOf = { 234 android.Manifest.permission.MANAGE_ACTIVITY_TASKS, 235 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) 236 @Override registerUserVisibleJobObserver(@onNull IUserVisibleJobObserver observer)237 public void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { 238 try { 239 mBinder.registerUserVisibleJobObserver(observer); 240 } catch (RemoteException e) { 241 } 242 } 243 244 @RequiresPermission(allOf = { 245 android.Manifest.permission.MANAGE_ACTIVITY_TASKS, 246 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) 247 @Override unregisterUserVisibleJobObserver(@onNull IUserVisibleJobObserver observer)248 public void unregisterUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) { 249 try { 250 mBinder.unregisterUserVisibleJobObserver(observer); 251 } catch (RemoteException e) { 252 } 253 } 254 255 @RequiresPermission(allOf = { 256 android.Manifest.permission.MANAGE_ACTIVITY_TASKS, 257 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) 258 @Override notePendingUserRequestedAppStop(@onNull String packageName, int userId, @Nullable String debugReason)259 public void notePendingUserRequestedAppStop(@NonNull String packageName, int userId, 260 @Nullable String debugReason) { 261 try { 262 mBinder.notePendingUserRequestedAppStop(packageName, userId, debugReason); 263 } catch (RemoteException e) { 264 } 265 } 266 } 267