1 /* 2 * Copyright (C) 2019 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 package android.jobscheduler.cts; 17 18 import static android.jobscheduler.cts.jobtestapp.TestJobService.ACTION_JOB_STARTED; 19 import static android.jobscheduler.cts.jobtestapp.TestJobService.ACTION_JOB_STOPPED; 20 import static android.jobscheduler.cts.jobtestapp.TestJobService.JOB_PARAMS_EXTRA_KEY; 21 22 import android.app.job.JobParameters; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.jobscheduler.cts.jobtestapp.TestActivity; 29 import android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver; 30 import android.os.SystemClock; 31 import android.util.Log; 32 33 /** 34 * Common functions to interact with the test app. 35 */ 36 class TestAppInterface { 37 private static final String TAG = TestAppInterface.class.getSimpleName(); 38 39 static final String TEST_APP_PACKAGE = "android.jobscheduler.cts.jobtestapp"; 40 private static final String TEST_APP_ACTIVITY = TEST_APP_PACKAGE + ".TestActivity"; 41 static final String TEST_APP_RECEIVER = TEST_APP_PACKAGE + ".TestJobSchedulerReceiver"; 42 43 private final Context mContext; 44 private final int mJobId; 45 46 /* accesses must be synchronized on itself */ 47 private final TestJobStatus mTestJobStatus = new TestJobStatus(); 48 TestAppInterface(Context ctx, int jobId)49 TestAppInterface(Context ctx, int jobId) { 50 mContext = ctx; 51 mJobId = jobId; 52 53 final IntentFilter intentFilter = new IntentFilter(); 54 intentFilter.addAction(ACTION_JOB_STARTED); 55 intentFilter.addAction(ACTION_JOB_STOPPED); 56 mContext.registerReceiver(mReceiver, intentFilter); 57 } 58 cleanup()59 void cleanup() { 60 final Intent cancelJobsIntent = new Intent(TestJobSchedulerReceiver.ACTION_CANCEL_JOBS); 61 cancelJobsIntent.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_RECEIVER)); 62 cancelJobsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 63 mContext.sendBroadcast(cancelJobsIntent); 64 mContext.sendBroadcast(new Intent(TestActivity.ACTION_FINISH_ACTIVITY)); 65 mContext.unregisterReceiver(mReceiver); 66 mTestJobStatus.reset(); 67 } 68 scheduleJob(boolean allowWhileIdle, boolean needNetwork)69 void scheduleJob(boolean allowWhileIdle, boolean needNetwork) { 70 final Intent scheduleJobIntent = new Intent(TestJobSchedulerReceiver.ACTION_SCHEDULE_JOB); 71 scheduleJobIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 72 scheduleJobIntent.putExtra(TestJobSchedulerReceiver.EXTRA_JOB_ID_KEY, mJobId); 73 scheduleJobIntent.putExtra(TestJobSchedulerReceiver.EXTRA_ALLOW_IN_IDLE, allowWhileIdle); 74 scheduleJobIntent.putExtra(TestJobSchedulerReceiver.EXTRA_REQUIRE_NETWORK_ANY, needNetwork); 75 scheduleJobIntent.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_RECEIVER)); 76 mContext.sendBroadcast(scheduleJobIntent); 77 } 78 startAndKeepTestActivity()79 void startAndKeepTestActivity() { 80 final Intent testActivity = new Intent(); 81 testActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 82 testActivity.setComponent(new ComponentName(TEST_APP_PACKAGE, TEST_APP_ACTIVITY)); 83 mContext.startActivity(testActivity); 84 } 85 86 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 87 @Override 88 public void onReceive(Context context, Intent intent) { 89 Log.d(TAG, "Received action " + intent.getAction()); 90 switch (intent.getAction()) { 91 case ACTION_JOB_STARTED: 92 case ACTION_JOB_STOPPED: 93 final JobParameters params = intent.getParcelableExtra(JOB_PARAMS_EXTRA_KEY); 94 Log.d(TAG, "JobId: " + params.getJobId()); 95 synchronized (mTestJobStatus) { 96 mTestJobStatus.running = ACTION_JOB_STARTED.equals(intent.getAction()); 97 mTestJobStatus.jobId = params.getJobId(); 98 } 99 break; 100 } 101 } 102 }; 103 awaitJobStart(long maxWait)104 boolean awaitJobStart(long maxWait) throws Exception { 105 return waitUntilTrue(maxWait, () -> { 106 synchronized (mTestJobStatus) { 107 return (mTestJobStatus.jobId == mJobId) && mTestJobStatus.running; 108 } 109 }); 110 } 111 112 boolean awaitJobStop(long maxWait) throws Exception { 113 return waitUntilTrue(maxWait, () -> { 114 synchronized (mTestJobStatus) { 115 return (mTestJobStatus.jobId == mJobId) && !mTestJobStatus.running; 116 } 117 }); 118 } 119 120 private boolean waitUntilTrue(long maxWait, Condition condition) throws Exception { 121 final long deadLine = SystemClock.uptimeMillis() + maxWait; 122 do { 123 Thread.sleep(500); 124 } while (!condition.isTrue() && SystemClock.uptimeMillis() < deadLine); 125 return condition.isTrue(); 126 } 127 128 private static final class TestJobStatus { 129 int jobId; 130 boolean running; 131 132 private void reset() { 133 running = false; 134 } 135 } 136 137 private interface Condition { 138 boolean isTrue() throws Exception; 139 } 140 } 141