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}