Home | History | Annotate | Download | only in jobscheduler
      1 /*
      2  * Copyright (C) 2016 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.jobscheduler;
     18 
     19 import android.annotation.TargetApi;
     20 import android.app.job.JobInfo;
     21 import android.app.job.JobParameters;
     22 import android.app.job.JobScheduler;
     23 import android.app.job.JobService;
     24 import android.content.Context;
     25 import android.os.Handler;
     26 import android.util.Log;
     27 
     28 import java.util.concurrent.CountDownLatch;
     29 import java.util.concurrent.TimeUnit;
     30 
     31 /**
     32  * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this
     33  * class is configured through the static
     34  * {@link TestEnvironment}.
     35  */
     36 @TargetApi(21)
     37 public class TriggerContentJobService extends JobService {
     38     private static final String TAG = "TriggerContentJobService";
     39 
     40     /** Wait this long before timing out the test. */
     41     private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds.
     42 
     43     /** How long to delay before rescheduling the job each time we repeat. */
     44     private static final long REPEAT_INTERVAL = 1000L; // 1 second.
     45 
     46     JobInfo mRunningJobInfo;
     47     JobParameters mRunningParams;
     48 
     49     final Handler mHandler = new Handler();
     50     final Runnable mWorker = new Runnable() {
     51         @Override public void run() {
     52             scheduleJob(TriggerContentJobService.this, mRunningJobInfo);
     53             jobFinished(mRunningParams, false);
     54         }
     55     };
     56 
     57     public static void scheduleJob(Context context, JobInfo jobInfo) {
     58         JobScheduler js = context.getSystemService(JobScheduler.class);
     59         js.schedule(jobInfo);
     60     }
     61 
     62     @Override
     63     public void onCreate() {
     64         super.onCreate();
     65         Log.e(TAG, "Created test service.");
     66     }
     67 
     68     @Override
     69     public boolean onStartJob(JobParameters params) {
     70         Log.i(TAG, "Test job executing: " + params.getJobId());
     71 
     72         int mode = TestEnvironment.getTestEnvironment().getMode();
     73         mRunningJobInfo = TestEnvironment.getTestEnvironment().getModeJobInfo();
     74         TestEnvironment.getTestEnvironment().setMode(TestEnvironment.MODE_ONESHOT, null);
     75         TestEnvironment.getTestEnvironment().notifyExecution(params);
     76 
     77         if (mode == TestEnvironment.MODE_ONE_REPEAT) {
     78             mRunningParams = params;
     79             mHandler.postDelayed(mWorker, REPEAT_INTERVAL);
     80             return true;
     81         } else {
     82             return false;  // No work to do.
     83         }
     84     }
     85 
     86     @Override
     87     public boolean onStopJob(JobParameters params) {
     88         return false;
     89     }
     90 
     91     /**
     92      * Configures the expected behaviour for each test. This object is shared across consecutive
     93      * tests, so to clear state each test is responsible for calling
     94      * {@link TestEnvironment#setUp()}.
     95      */
     96     public static final class TestEnvironment {
     97 
     98         private static TestEnvironment kTestEnvironment;
     99         //public static final int INVALID_JOB_ID = -1;
    100 
    101         private CountDownLatch mLatch;
    102         private JobParameters mExecutedJobParameters;
    103         private int mMode;
    104         private JobInfo mModeJobInfo;
    105 
    106         public static final int MODE_ONESHOT = 0;
    107         public static final int MODE_ONE_REPEAT = 1;
    108 
    109         public static TestEnvironment getTestEnvironment() {
    110             if (kTestEnvironment == null) {
    111                 kTestEnvironment = new TestEnvironment();
    112             }
    113             return kTestEnvironment;
    114         }
    115 
    116         public JobParameters getLastJobParameters() {
    117             return mExecutedJobParameters;
    118         }
    119 
    120         /**
    121          * Block the test thread, waiting on the JobScheduler to execute some previously scheduled
    122          * job on this service.
    123          */
    124         public boolean awaitExecution() throws InterruptedException {
    125             final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    126             return executed;
    127         }
    128 
    129         public void setMode(int mode, JobInfo jobInfo) {
    130             synchronized (this) {
    131                 mMode = mode;
    132                 mModeJobInfo = jobInfo;
    133             }
    134         }
    135 
    136         public int getMode() {
    137             synchronized (this) {
    138                 return mMode;
    139             }
    140         }
    141 
    142         public JobInfo getModeJobInfo() {
    143             synchronized (this) {
    144                 return mModeJobInfo;
    145             }
    146         }
    147 
    148         /**
    149          * Block the test thread, expecting to timeout but still listening to ensure that no jobs
    150          * land in the interim.
    151          * @return True if the latch timed out waiting on an execution.
    152          */
    153         public boolean awaitTimeout() throws InterruptedException {
    154             return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    155         }
    156 
    157         private void notifyExecution(JobParameters params) {
    158             Log.d(TAG, "Job executed:" + params.getJobId());
    159             mExecutedJobParameters = params;
    160             mLatch.countDown();
    161         }
    162 
    163         public void setExpectedExecutions(int numExecutions) {
    164             // For no executions expected, set count to 1 so we can still block for the timeout.
    165             if (numExecutions == 0) {
    166                 mLatch = new CountDownLatch(1);
    167             } else {
    168                 mLatch = new CountDownLatch(numExecutions);
    169             }
    170         }
    171 
    172         /** Called in each testCase#setup */
    173         public void setUp() {
    174             mLatch = null;
    175             mExecutedJobParameters = null;
    176         }
    177 
    178     }
    179 }