1 /* 2 * Copyright (C) 2014 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 com.android.cts.verifier.jobscheduler; 18 19 import com.android.cts.verifier.R; 20 21 import android.annotation.TargetApi; 22 import android.app.job.JobInfo; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.os.AsyncTask; 28 import android.os.Bundle; 29 import android.os.PowerManager; 30 import android.util.Log; 31 import android.view.View; 32 import android.widget.Button; 33 import android.widget.ImageView; 34 import android.widget.TextView; 35 36 /** 37 * Idle constraints: 38 * The framework doesn't support turning the screen off. Use the manual tester to 39 * turn off the screen to run to run tests that require idle mode to be on. 40 */ 41 @TargetApi(21) 42 public class IdleConstraintTestActivity extends ConstraintTestActivity { 43 private static final String TAG = "IdleModeTestActivity"; 44 /** 45 * It takes >1hr for idle mode to be triggered. We'll use this secret broadcast to force the 46 * scheduler into idle. It's not a protected broadcast so that's alright. 47 */ 48 private static final String ACTION_EXPEDITE_IDLE_MODE = 49 "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"; 50 51 /** 52 * Id for the job that we schedule when the device is not in idle mode. This job is expected 53 * to not execute. Executing means that the verifier test should fail. 54 */ 55 private static final int IDLE_OFF_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 0; 56 /** 57 * Id for the job that we schedule when the device *is* in idle mode. This job is expected to 58 * execute. Not executing means that the verifier test should fail. 59 */ 60 private static final int IDLE_ON_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 1; 61 62 private static final int IDLE_ON_TEST_STATE_NOT_IN_PROGRESS = 0; 63 private static final int IDLE_ON_TEST_STATE_WAITING_FOR_SCREEN_OFF = 1; 64 65 /** 66 * mTestState stores the state of the tests. It is used to ensure that we only run 67 * the 'idle on' test if screen is turned off after the user has started tests. 68 */ 69 private int mTestState = IDLE_ON_TEST_STATE_NOT_IN_PROGRESS; 70 71 private PowerManager mPowerManager; 72 private TextView mContinueInstructionTextView; 73 74 /** 75 * Listens for screen off event. Starts an async task to force device into 76 * idle mode and run the 'idle on' test. 77 */ 78 private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { 79 @Override 80 public void onReceive(Context context, Intent intent) { 81 if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { 82 if (mTestState == IDLE_ON_TEST_STATE_WAITING_FOR_SCREEN_OFF) { 83 mContinueInstructionTextView.setVisibility(View.GONE); 84 PowerManager.WakeLock wl = mPowerManager.newWakeLock( 85 PowerManager.PARTIAL_WAKE_LOCK, TAG); 86 wl.acquire(); 87 new TestIdleModeTaskIdle().execute(wl); 88 } 89 } else { 90 Log.e(TAG, "Invalid broadcast received, was expecting SCREEN_OFF"); 91 } 92 } 93 }; 94 95 @Override 96 protected void onCreate(Bundle savedInstanceState) { 97 super.onCreate(savedInstanceState); 98 99 // Set up the UI. 100 setContentView(R.layout.js_idle); 101 setPassFailButtonClickListeners(); 102 setInfoResources(R.string.js_idle_test, R.string.js_idle_instructions, -1); 103 mStartButton = (Button) findViewById(R.id.js_idle_start_test_button); 104 mContinueInstructionTextView = (TextView) findViewById( 105 R.id.js_idle_continue_instruction_view); 106 107 // Register receiver for screen off event. 108 IntentFilter intentFilter = new IntentFilter(); 109 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 110 111 mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 112 113 registerReceiver(mScreenOffReceiver, intentFilter); 114 115 } 116 117 @Override 118 protected void onResume() { 119 super.onResume(); 120 // Enable start button only if tests are not in progress. 121 if (mTestState == IDLE_ON_TEST_STATE_NOT_IN_PROGRESS) { 122 mStartButton.setEnabled(true); 123 mContinueInstructionTextView.setVisibility(View.GONE); 124 } 125 } 126 127 @Override 128 protected void onDestroy() { 129 super.onDestroy(); 130 unregisterReceiver(mScreenOffReceiver); 131 } 132 133 @Override 134 protected void startTestImpl() { 135 mStartButton.setEnabled(false); 136 new TestIdleModeTaskNotIdle().execute(); 137 } 138 139 /** Background task that will run the 'not idle' test. */ 140 private class TestIdleModeTaskNotIdle extends AsyncTask<Void, Void, Void> { 141 @Override 142 protected Void doInBackground(Void... voids) { 143 testIdleConstraintFails_notIdle(); 144 return null; 145 } 146 147 @Override 148 protected void onPostExecute(Void result) { 149 mTestState = IDLE_ON_TEST_STATE_WAITING_FOR_SCREEN_OFF; 150 mContinueInstructionTextView.setVisibility(View.VISIBLE); 151 } 152 } 153 154 /** Background task that will run the 'idle' test. */ 155 private class TestIdleModeTaskIdle extends AsyncTask<PowerManager.WakeLock, Void, Void> { 156 157 private PowerManager.WakeLock mPartialWakeLock; 158 159 @Override 160 protected Void doInBackground(PowerManager.WakeLock... wakeLocks) { 161 mPartialWakeLock = wakeLocks[0]; 162 163 if (!sendBroadcastAndBlockForResult(new Intent(ACTION_EXPEDITE_IDLE_MODE))) { 164 runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, false)); 165 } else { 166 testIdleConstraintExecutes_onIdle(); 167 } 168 notifyTestCompleted(); 169 return null; 170 } 171 172 @Override 173 protected void onPostExecute(Void result) { 174 // Reset test state 175 mTestState = IDLE_ON_TEST_STATE_NOT_IN_PROGRESS; 176 177 PowerManager.WakeLock fullWakeLock = mPowerManager.newWakeLock( 178 PowerManager.FULL_WAKE_LOCK 179 | PowerManager.ACQUIRE_CAUSES_WAKEUP 180 | PowerManager.ON_AFTER_RELEASE, TAG); 181 // Turn on screen and release both locks 182 fullWakeLock.acquire(); 183 fullWakeLock.release(); 184 mPartialWakeLock.release(); 185 } 186 } 187 188 /** 189 * The user has just pressed the "Start Test" button, so we know that the device can't be idle. 190 * Schedule a job with an idle constraint and verify that it doesn't execute. 191 */ 192 private void testIdleConstraintFails_notIdle() { 193 mTestEnvironment.setUp(); 194 mJobScheduler.cancelAll(); 195 196 mTestEnvironment.setExpectedExecutions(0); 197 198 mJobScheduler.schedule( 199 new JobInfo.Builder(IDLE_OFF_JOB_ID, mMockComponent) 200 .setRequiresDeviceIdle(true) 201 .build()); 202 203 boolean testPassed; 204 try { 205 testPassed = mTestEnvironment.awaitTimeout(); 206 } catch (InterruptedException e) { 207 // We'll just indicate that it failed, not why. 208 testPassed = false; 209 } 210 runOnUiThread(new IdleTestResultRunner(IDLE_OFF_JOB_ID, testPassed)); 211 } 212 213 /** 214 * Called after screen is switched off and device is forced into idle mode. 215 * Schedule a job with an idle constraint and verify that it executes. 216 */ 217 private void testIdleConstraintExecutes_onIdle() { 218 mTestEnvironment.setUp(); 219 mJobScheduler.cancelAll(); 220 221 mTestEnvironment.setExpectedExecutions(1); 222 223 mJobScheduler.schedule( 224 new JobInfo.Builder(IDLE_ON_JOB_ID, mMockComponent) 225 .setRequiresDeviceIdle(true) 226 .build()); 227 228 boolean testPassed; 229 try { 230 testPassed = mTestEnvironment.awaitExecution(); 231 } catch (InterruptedException e) { 232 // We'll just indicate that it failed, not why. 233 testPassed = false; 234 } 235 236 runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, testPassed)); 237 } 238 239 /** 240 * Runnable to update the UI with the outcome of the test. This class only runs two tests, so 241 * the argument passed into the constructor will indicate which of the tests we are reporting 242 * for. 243 */ 244 protected class IdleTestResultRunner extends TestResultRunner { 245 246 IdleTestResultRunner(int jobId, boolean testPassed) { 247 super(jobId, testPassed); 248 } 249 250 @Override 251 public void run() { 252 ImageView view; 253 if (mJobId == IDLE_OFF_JOB_ID) { 254 view = (ImageView) findViewById(R.id.idle_off_test_image); 255 } else if (mJobId == IDLE_ON_JOB_ID) { 256 view = (ImageView) findViewById(R.id.idle_on_test_image); 257 } else { 258 noteInvalidTest(); 259 return; 260 } 261 view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error); 262 } 263 } 264 } 265