16e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams/* 26e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * Copyright (C) 2014 The Android Open Source Project 36e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 46e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * Licensed under the Apache License, Version 2.0 (the "License"); 56e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * you may not use this file except in compliance with the License. 66e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * You may obtain a copy of the License at 76e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 86e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * http://www.apache.org/licenses/LICENSE-2.0 96e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 106e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * Unless required by applicable law or agreed to in writing, software 116e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * distributed under the License is distributed on an "AS IS" BASIS, 126e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * See the License for the specific language governing permissions and 146e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * limitations under the License 156e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 166e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 177060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tatepackage android.app.job; 186e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 196e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.app.Service; 206e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.content.Intent; 216e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.os.Handler; 226e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.os.IBinder; 236e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.os.Looper; 246e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.os.Message; 256e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.os.RemoteException; 266e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport android.util.Log; 276e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 286e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williamsimport com.android.internal.annotations.GuardedBy; 296e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 306e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams/** 317060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * <p>Entry point for the callback from the {@link android.app.job.JobScheduler}.</p> 326e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * <p>This is the base class that handles asynchronous requests that were previously scheduled. You 337060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * are responsible for overriding {@link JobService#onStartJob(JobParameters)}, which is where 347060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * you will implement your job logic.</p> 357060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * <p>This service executes each incoming job on a {@link android.os.Handler} running on your 366e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * application's main thread. This means that you <b>must</b> offload your execution logic to 376e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result 387060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * in blocking any future callbacks from the JobManager - specifically 397060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * {@link #onStopJob(android.app.job.JobParameters)}, which is meant to inform you that the 406e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * scheduling requirements are no longer being met.</p> 416e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 427060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tatepublic abstract class JobService extends Service { 437060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private static final String TAG = "JobService"; 446e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 456e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 467060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * Job services must be protected with this permission: 476e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 486e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * <pre class="prettyprint"> 497060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * <service android:name="MyJobService" 507060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * android:permission="android.permission.BIND_JOB_SERVICE" > 516e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * ... 526e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * </service> 536e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * </pre> 546e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 557060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * <p>If a job service is declared in the manifest but not protected with this 566e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * permission, that service will be ignored by the OS. 576e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 586e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams public static final String PERMISSION_BIND = 597060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate "android.permission.BIND_JOB_SERVICE"; 606e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 616e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 626e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * Identifier for a message that will result in a call to 637060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * {@link #onStartJob(android.app.job.JobParameters)}. 646e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 657060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private final int MSG_EXECUTE_JOB = 0; 666e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 677060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}. 686e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 697060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private final int MSG_STOP_JOB = 1; 706e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 717060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * Message that the client has completed execution of this job. 726e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 737060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private final int MSG_JOB_FINISHED = 2; 746e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 756e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** Lock object for {@link #mHandler}. */ 766e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams private final Object mHandlerLock = new Object(); 776e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 786e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 797060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * Handler we post jobs to. Responsible for calling into the client logic, and handling the 806e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * callback to the system. 816e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 826e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams @GuardedBy("mHandlerLock") 837060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobHandler mHandler; 846e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 856e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** Binder for this service. */ 867060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate IJobService mBinder = new IJobService.Stub() { 876e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams @Override 887060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public void startJob(JobParameters jobParams) { 896e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams ensureHandler(); 907060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams); 916e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams m.sendToTarget(); 926e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 936e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams @Override 947060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public void stopJob(JobParameters jobParams) { 956e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams ensureHandler(); 967060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams); 976e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams m.sendToTarget(); 986e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 996e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams }; 1006e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 1016e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** @hide */ 1026e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams void ensureHandler() { 1036e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams synchronized (mHandlerLock) { 1046e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams if (mHandler == null) { 1057060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate mHandler = new JobHandler(getMainLooper()); 1066e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1076e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1086e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1096e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 1106e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 1116e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * Runs on application's main thread - callbacks are meant to offboard work to some other 1126e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * (app-specified) mechanism. 1136e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * @hide 1146e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 1157060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate class JobHandler extends Handler { 1167060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate JobHandler(Looper looper) { 1176e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams super(looper); 1186e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1196e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 1206e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams @Override 1216e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams public void handleMessage(Message msg) { 1227060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final JobParameters params = (JobParameters) msg.obj; 1236e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams switch (msg.what) { 1247060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate case MSG_EXECUTE_JOB: 1256e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams try { 1267060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate boolean workOngoing = JobService.this.onStartJob(params); 127691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams ackStartMessage(params, workOngoing); 1286e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } catch (Exception e) { 1297060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.e(TAG, "Error while executing job: " + params.getJobId()); 1306e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams throw new RuntimeException(e); 1316e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1326e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams break; 1337060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate case MSG_STOP_JOB: 1346e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams try { 1357060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate boolean ret = JobService.this.onStopJob(params); 136691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams ackStopMessage(params, ret); 1376e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } catch (Exception e) { 1387060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.e(TAG, "Application unable to handle onStopJob.", e); 1396e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams throw new RuntimeException(e); 1406e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1416e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams break; 1427060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate case MSG_JOB_FINISHED: 1436e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams final boolean needsReschedule = (msg.arg2 == 1); 1447060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate IJobCallback callback = params.getCallback(); 1456e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams if (callback != null) { 1466e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams try { 1477060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate callback.jobFinished(params.getJobId(), needsReschedule); 1486e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } catch (RemoteException e) { 1497060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.e(TAG, "Error reporting job finish to system: binder has gone" + 1506e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams "away."); 1516e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1526e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } else { 1537060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.e(TAG, "finishJob() called for a nonexistent job id."); 1546e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1556e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams break; 1566e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams default: 1576e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams Log.e(TAG, "Unrecognised message received."); 1586e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams break; 1596e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1606e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1616e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 1627060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private void ackStartMessage(JobParameters params, boolean workOngoing) { 1637060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final IJobCallback callback = params.getCallback(); 1647060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final int jobId = params.getJobId(); 1656e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams if (callback != null) { 1666e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams try { 1677060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate callback.acknowledgeStartMessage(jobId, workOngoing); 1686e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } catch(RemoteException e) { 1697060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.e(TAG, "System unreachable for starting job."); 1706e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1716e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } else { 1726e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams if (Log.isLoggable(TAG, Log.DEBUG)) { 1737060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.d(TAG, "Attempting to ack a job that has already been processed."); 174691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams } 175691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams } 176691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams } 177691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams 1787060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate private void ackStopMessage(JobParameters params, boolean reschedule) { 1797060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final IJobCallback callback = params.getCallback(); 1807060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate final int jobId = params.getJobId(); 181691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams if (callback != null) { 182691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams try { 1837060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate callback.acknowledgeStopMessage(jobId, reschedule); 184691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams } catch(RemoteException e) { 1857060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.e(TAG, "System unreachable for stopping job."); 186691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams } 187691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams } else { 188691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams if (Log.isLoggable(TAG, Log.DEBUG)) { 1897060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Log.d(TAG, "Attempting to ack a job that has already been processed."); 1906e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1916e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1926e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1936e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1946e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 1956e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** @hide */ 1966e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams public final IBinder onBind(Intent intent) { 1976e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams return mBinder.asBinder(); 1986e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 1996e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 2006e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 2017060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * Override this method with the callback logic for your job. Any such logic needs to be 2026e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * performed on a separate thread, as this function is executed on your application's main 2036e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * thread. 2046e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 2057060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * @param params Parameters specifying info about this job, including the extras bundle you 2067060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * optionally provided at job-creation time. 207691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams * @return True if your service needs to process the work (on a separate thread). False if 2087060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * there's no more work to be done for this job. 2096e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 2107060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public abstract boolean onStartJob(JobParameters params); 2116e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 2126e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 2137060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * This method is called if the system has determined that you must stop execution of your job 2147060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * even before you've had a chance to call {@link #jobFinished(JobParameters, boolean)}. 2156e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 2166e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * <p>This will happen if the requirements specified at schedule time are no longer met. For 2176e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * example you may have requested WiFi with 218d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams * {@link android.app.job.JobInfo.Builder#setRequiredNetworkType(int)}, yet while your 2197060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * job was executing the user toggled WiFi. Another example is if you had specified 2207060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its 2216e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * idle maintenance window. You are solely responsible for the behaviour of your application 2226e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * upon receipt of this message; your app will likely start to misbehave if you ignore it. One 223691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams * immediate repercussion is that the system will cease holding a wakelock for you.</p> 2246e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 2257060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * @param params Parameters specifying info about this job. 2267060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * @return True to indicate to the JobManager whether you'd like to reschedule this job based 2277060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * on the retry criteria provided at job creation-time. False to drop the job. Regardless of 2287060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * the value returned, your job must stop executing. 2296e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 2307060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public abstract boolean onStopJob(JobParameters params); 2316e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams 2326e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams /** 2337060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * Callback to inform the JobManager you've finished executing. This can be called from any 2346e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * thread, as it will ultimately be run on your application's main thread. When the system 2356e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * receives this message it will release the wakelock being held. 2366e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * <p> 237691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams * You can specify post-execution behaviour to the scheduler here with 2387060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * <code>needsReschedule </code>. This will apply a back-off timer to your job based on 239691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams * the default, or what was set with 2407060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}. The original 2417060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * requirements are always honoured even for a backed-off job. Note that a job running in 2427060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * idle mode will not be backed-off. Instead what will happen is the job will be re-added 243691e93e82cf97338a760c5fbf900ef29ed9224c2Matthew Williams * to the queue and re-executed within a future idle maintenance window. 2446e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * </p> 2456e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams * 2467060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * @param params Parameters specifying system-provided info about this job, this was given to 2477060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate * your application in {@link #onStartJob(JobParameters)}. 248d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams * @param needsReschedule True if this job should be rescheduled according to the back-off 249d1c06753d045ad10e00e7aba53ee2adba0712cccMatthew Williams * criteria specified at schedule-time. False otherwise. 2506e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams */ 2517060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate public final void jobFinished(JobParameters params, boolean needsReschedule) { 2526e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams ensureHandler(); 2537060b04f6d92351b67222e636ab378a0273bf3e7Christopher Tate Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params); 2546e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams m.arg2 = needsReschedule ? 1 : 0; 2556e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams m.sendToTarget(); 2566e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams } 2576e31c5c82bc5c9bddf9c01d254067ea5bebbd96bMatthew Williams}