1*b7c941bbSAndroid Build Coastguard Worker /* 2*b7c941bbSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 3*b7c941bbSAndroid Build Coastguard Worker * 4*b7c941bbSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*b7c941bbSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*b7c941bbSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*b7c941bbSAndroid Build Coastguard Worker * 8*b7c941bbSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*b7c941bbSAndroid Build Coastguard Worker * 10*b7c941bbSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*b7c941bbSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*b7c941bbSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*b7c941bbSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*b7c941bbSAndroid Build Coastguard Worker * limitations under the License. 15*b7c941bbSAndroid Build Coastguard Worker */ 16*b7c941bbSAndroid Build Coastguard Worker 17*b7c941bbSAndroid Build Coastguard Worker package android.jobscheduler; 18*b7c941bbSAndroid Build Coastguard Worker 19*b7c941bbSAndroid Build Coastguard Worker import android.annotation.TargetApi; 20*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobInfo; 21*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobParameters; 22*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobScheduler; 23*b7c941bbSAndroid Build Coastguard Worker import android.app.job.JobService; 24*b7c941bbSAndroid Build Coastguard Worker import android.content.Context; 25*b7c941bbSAndroid Build Coastguard Worker import android.os.Handler; 26*b7c941bbSAndroid Build Coastguard Worker import android.util.Log; 27*b7c941bbSAndroid Build Coastguard Worker 28*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.CountDownLatch; 29*b7c941bbSAndroid Build Coastguard Worker import java.util.concurrent.TimeUnit; 30*b7c941bbSAndroid Build Coastguard Worker 31*b7c941bbSAndroid Build Coastguard Worker /** 32*b7c941bbSAndroid Build Coastguard Worker * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this 33*b7c941bbSAndroid Build Coastguard Worker * class is configured through the static 34*b7c941bbSAndroid Build Coastguard Worker * {@link TestEnvironment}. 35*b7c941bbSAndroid Build Coastguard Worker */ 36*b7c941bbSAndroid Build Coastguard Worker @TargetApi(21) 37*b7c941bbSAndroid Build Coastguard Worker public class TriggerContentJobService extends JobService { 38*b7c941bbSAndroid Build Coastguard Worker private static final String TAG = "TriggerContentJobService"; 39*b7c941bbSAndroid Build Coastguard Worker 40*b7c941bbSAndroid Build Coastguard Worker /** Wait this long before timing out the test. */ 41*b7c941bbSAndroid Build Coastguard Worker private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds. 42*b7c941bbSAndroid Build Coastguard Worker 43*b7c941bbSAndroid Build Coastguard Worker /** How long to delay before rescheduling the job each time we repeat. */ 44*b7c941bbSAndroid Build Coastguard Worker private static final long REPEAT_INTERVAL = 1000L; // 1 second. 45*b7c941bbSAndroid Build Coastguard Worker 46*b7c941bbSAndroid Build Coastguard Worker JobInfo mRunningJobInfo; 47*b7c941bbSAndroid Build Coastguard Worker JobParameters mRunningParams; 48*b7c941bbSAndroid Build Coastguard Worker 49*b7c941bbSAndroid Build Coastguard Worker final Handler mHandler = new Handler(); 50*b7c941bbSAndroid Build Coastguard Worker final Runnable mWorkerReschedule = new Runnable() { 51*b7c941bbSAndroid Build Coastguard Worker @Override public void run() { 52*b7c941bbSAndroid Build Coastguard Worker scheduleJob(TriggerContentJobService.this, mRunningJobInfo); 53*b7c941bbSAndroid Build Coastguard Worker jobFinished(mRunningParams, false); 54*b7c941bbSAndroid Build Coastguard Worker } 55*b7c941bbSAndroid Build Coastguard Worker }; 56*b7c941bbSAndroid Build Coastguard Worker final Runnable mWorkerFinishTrue = new Runnable() { 57*b7c941bbSAndroid Build Coastguard Worker @Override public void run() { 58*b7c941bbSAndroid Build Coastguard Worker jobFinished(mRunningParams, true); 59*b7c941bbSAndroid Build Coastguard Worker } 60*b7c941bbSAndroid Build Coastguard Worker }; 61*b7c941bbSAndroid Build Coastguard Worker scheduleJob(Context context, JobInfo jobInfo)62*b7c941bbSAndroid Build Coastguard Worker public static void scheduleJob(Context context, JobInfo jobInfo) { 63*b7c941bbSAndroid Build Coastguard Worker JobScheduler js = context.getSystemService(JobScheduler.class); 64*b7c941bbSAndroid Build Coastguard Worker js.schedule(jobInfo); 65*b7c941bbSAndroid Build Coastguard Worker } 66*b7c941bbSAndroid Build Coastguard Worker 67*b7c941bbSAndroid Build Coastguard Worker @Override onCreate()68*b7c941bbSAndroid Build Coastguard Worker public void onCreate() { 69*b7c941bbSAndroid Build Coastguard Worker super.onCreate(); 70*b7c941bbSAndroid Build Coastguard Worker Log.e(TAG, "Created test service."); 71*b7c941bbSAndroid Build Coastguard Worker } 72*b7c941bbSAndroid Build Coastguard Worker 73*b7c941bbSAndroid Build Coastguard Worker @Override onStartJob(JobParameters params)74*b7c941bbSAndroid Build Coastguard Worker public boolean onStartJob(JobParameters params) { 75*b7c941bbSAndroid Build Coastguard Worker Log.i(TAG, "Test job executing: " + params.getJobId()); 76*b7c941bbSAndroid Build Coastguard Worker 77*b7c941bbSAndroid Build Coastguard Worker int mode = TestEnvironment.getTestEnvironment().getMode(); 78*b7c941bbSAndroid Build Coastguard Worker mRunningJobInfo = TestEnvironment.getTestEnvironment().getModeJobInfo(); 79*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().setMode(TestEnvironment.MODE_ONESHOT, null); 80*b7c941bbSAndroid Build Coastguard Worker TestEnvironment.getTestEnvironment().notifyExecution(params); 81*b7c941bbSAndroid Build Coastguard Worker 82*b7c941bbSAndroid Build Coastguard Worker if (mode == TestEnvironment.MODE_ONE_REPEAT_RESCHEDULE) { 83*b7c941bbSAndroid Build Coastguard Worker mRunningParams = params; 84*b7c941bbSAndroid Build Coastguard Worker mHandler.postDelayed(mWorkerReschedule, REPEAT_INTERVAL); 85*b7c941bbSAndroid Build Coastguard Worker return true; 86*b7c941bbSAndroid Build Coastguard Worker } else if (mode == TestEnvironment.MODE_ONE_REPEAT_FINISH_TRUE) { 87*b7c941bbSAndroid Build Coastguard Worker mRunningParams = params; 88*b7c941bbSAndroid Build Coastguard Worker mHandler.postDelayed(mWorkerFinishTrue, REPEAT_INTERVAL); 89*b7c941bbSAndroid Build Coastguard Worker return true; 90*b7c941bbSAndroid Build Coastguard Worker } else { 91*b7c941bbSAndroid Build Coastguard Worker return false; // No work to do. 92*b7c941bbSAndroid Build Coastguard Worker } 93*b7c941bbSAndroid Build Coastguard Worker } 94*b7c941bbSAndroid Build Coastguard Worker 95*b7c941bbSAndroid Build Coastguard Worker @Override onStopJob(JobParameters params)96*b7c941bbSAndroid Build Coastguard Worker public boolean onStopJob(JobParameters params) { 97*b7c941bbSAndroid Build Coastguard Worker return false; 98*b7c941bbSAndroid Build Coastguard Worker } 99*b7c941bbSAndroid Build Coastguard Worker 100*b7c941bbSAndroid Build Coastguard Worker /** 101*b7c941bbSAndroid Build Coastguard Worker * Configures the expected behaviour for each test. This object is shared across consecutive 102*b7c941bbSAndroid Build Coastguard Worker * tests, so to clear state each test is responsible for calling 103*b7c941bbSAndroid Build Coastguard Worker * {@link TestEnvironment#setUp()}. 104*b7c941bbSAndroid Build Coastguard Worker */ 105*b7c941bbSAndroid Build Coastguard Worker public static final class TestEnvironment { 106*b7c941bbSAndroid Build Coastguard Worker 107*b7c941bbSAndroid Build Coastguard Worker private static TestEnvironment kTestEnvironment; 108*b7c941bbSAndroid Build Coastguard Worker //public static final int INVALID_JOB_ID = -1; 109*b7c941bbSAndroid Build Coastguard Worker 110*b7c941bbSAndroid Build Coastguard Worker private CountDownLatch mLatch; 111*b7c941bbSAndroid Build Coastguard Worker private JobParameters mExecutedJobParameters; 112*b7c941bbSAndroid Build Coastguard Worker private int mMode; 113*b7c941bbSAndroid Build Coastguard Worker private JobInfo mModeJobInfo; 114*b7c941bbSAndroid Build Coastguard Worker 115*b7c941bbSAndroid Build Coastguard Worker public static final int MODE_ONESHOT = 0; 116*b7c941bbSAndroid Build Coastguard Worker public static final int MODE_ONE_REPEAT_RESCHEDULE = 1; 117*b7c941bbSAndroid Build Coastguard Worker public static final int MODE_ONE_REPEAT_FINISH_TRUE = 2; 118*b7c941bbSAndroid Build Coastguard Worker getTestEnvironment()119*b7c941bbSAndroid Build Coastguard Worker public static TestEnvironment getTestEnvironment() { 120*b7c941bbSAndroid Build Coastguard Worker if (kTestEnvironment == null) { 121*b7c941bbSAndroid Build Coastguard Worker kTestEnvironment = new TestEnvironment(); 122*b7c941bbSAndroid Build Coastguard Worker } 123*b7c941bbSAndroid Build Coastguard Worker return kTestEnvironment; 124*b7c941bbSAndroid Build Coastguard Worker } 125*b7c941bbSAndroid Build Coastguard Worker getLastJobParameters()126*b7c941bbSAndroid Build Coastguard Worker public JobParameters getLastJobParameters() { 127*b7c941bbSAndroid Build Coastguard Worker return mExecutedJobParameters; 128*b7c941bbSAndroid Build Coastguard Worker } 129*b7c941bbSAndroid Build Coastguard Worker 130*b7c941bbSAndroid Build Coastguard Worker /** 131*b7c941bbSAndroid Build Coastguard Worker * Block the test thread, waiting on the JobScheduler to execute some previously scheduled 132*b7c941bbSAndroid Build Coastguard Worker * job on this service. 133*b7c941bbSAndroid Build Coastguard Worker */ awaitExecution()134*b7c941bbSAndroid Build Coastguard Worker public boolean awaitExecution() throws InterruptedException { 135*b7c941bbSAndroid Build Coastguard Worker final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 136*b7c941bbSAndroid Build Coastguard Worker return executed; 137*b7c941bbSAndroid Build Coastguard Worker } 138*b7c941bbSAndroid Build Coastguard Worker setMode(int mode, JobInfo jobInfo)139*b7c941bbSAndroid Build Coastguard Worker public void setMode(int mode, JobInfo jobInfo) { 140*b7c941bbSAndroid Build Coastguard Worker synchronized (this) { 141*b7c941bbSAndroid Build Coastguard Worker mMode = mode; 142*b7c941bbSAndroid Build Coastguard Worker mModeJobInfo = jobInfo; 143*b7c941bbSAndroid Build Coastguard Worker } 144*b7c941bbSAndroid Build Coastguard Worker } 145*b7c941bbSAndroid Build Coastguard Worker getMode()146*b7c941bbSAndroid Build Coastguard Worker public int getMode() { 147*b7c941bbSAndroid Build Coastguard Worker synchronized (this) { 148*b7c941bbSAndroid Build Coastguard Worker return mMode; 149*b7c941bbSAndroid Build Coastguard Worker } 150*b7c941bbSAndroid Build Coastguard Worker } 151*b7c941bbSAndroid Build Coastguard Worker getModeJobInfo()152*b7c941bbSAndroid Build Coastguard Worker public JobInfo getModeJobInfo() { 153*b7c941bbSAndroid Build Coastguard Worker synchronized (this) { 154*b7c941bbSAndroid Build Coastguard Worker return mModeJobInfo; 155*b7c941bbSAndroid Build Coastguard Worker } 156*b7c941bbSAndroid Build Coastguard Worker } 157*b7c941bbSAndroid Build Coastguard Worker 158*b7c941bbSAndroid Build Coastguard Worker /** 159*b7c941bbSAndroid Build Coastguard Worker * Block the test thread, expecting to timeout but still listening to ensure that no jobs 160*b7c941bbSAndroid Build Coastguard Worker * land in the interim. 161*b7c941bbSAndroid Build Coastguard Worker * @return True if the latch timed out waiting on an execution. 162*b7c941bbSAndroid Build Coastguard Worker */ awaitTimeout()163*b7c941bbSAndroid Build Coastguard Worker public boolean awaitTimeout() throws InterruptedException { 164*b7c941bbSAndroid Build Coastguard Worker return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 165*b7c941bbSAndroid Build Coastguard Worker } 166*b7c941bbSAndroid Build Coastguard Worker notifyExecution(JobParameters params)167*b7c941bbSAndroid Build Coastguard Worker private void notifyExecution(JobParameters params) { 168*b7c941bbSAndroid Build Coastguard Worker Log.d(TAG, "Job executed:" + params.getJobId()); 169*b7c941bbSAndroid Build Coastguard Worker mExecutedJobParameters = params; 170*b7c941bbSAndroid Build Coastguard Worker mLatch.countDown(); 171*b7c941bbSAndroid Build Coastguard Worker } 172*b7c941bbSAndroid Build Coastguard Worker setExpectedExecutions(int numExecutions)173*b7c941bbSAndroid Build Coastguard Worker public void setExpectedExecutions(int numExecutions) { 174*b7c941bbSAndroid Build Coastguard Worker // For no executions expected, set count to 1 so we can still block for the timeout. 175*b7c941bbSAndroid Build Coastguard Worker if (numExecutions == 0) { 176*b7c941bbSAndroid Build Coastguard Worker mLatch = new CountDownLatch(1); 177*b7c941bbSAndroid Build Coastguard Worker } else { 178*b7c941bbSAndroid Build Coastguard Worker mLatch = new CountDownLatch(numExecutions); 179*b7c941bbSAndroid Build Coastguard Worker } 180*b7c941bbSAndroid Build Coastguard Worker } 181*b7c941bbSAndroid Build Coastguard Worker 182*b7c941bbSAndroid Build Coastguard Worker /** Called in each testCase#setup */ setUp()183*b7c941bbSAndroid Build Coastguard Worker public void setUp() { 184*b7c941bbSAndroid Build Coastguard Worker mLatch = null; 185*b7c941bbSAndroid Build Coastguard Worker mExecutedJobParameters = null; 186*b7c941bbSAndroid Build Coastguard Worker } 187*b7c941bbSAndroid Build Coastguard Worker 188*b7c941bbSAndroid Build Coastguard Worker } 189*b7c941bbSAndroid Build Coastguard Worker }