1 /* 2 * Copyright (C) 2018 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.cts; 18 19 import android.annotation.TargetApi; 20 import android.app.job.JobInfo; 21 import android.content.pm.PackageManager; 22 import android.os.SystemClock; 23 import android.support.test.uiautomator.UiDevice; 24 25 import androidx.test.InstrumentationRegistry; 26 27 /** 28 * Make sure the state of {@link android.app.job.JobScheduler} is correct. 29 */ 30 @TargetApi(28) 31 public class DeviceStatesTest extends ConstraintTest { 32 /** Unique identifier for the job scheduled by this suite of tests. */ 33 public static final int STATE_JOB_ID = DeviceStatesTest.class.hashCode(); 34 35 private JobInfo.Builder mBuilder; 36 private UiDevice mUiDevice; 37 38 @Override setUp()39 public void setUp() throws Exception { 40 super.setUp(); 41 mBuilder = new JobInfo.Builder(STATE_JOB_ID, kJobServiceComponent); 42 mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 43 } 44 45 @Override tearDown()46 public void tearDown() throws Exception { 47 mJobScheduler.cancel(STATE_JOB_ID); 48 // Put device back in to normal operation. 49 toggleScreenOn(true /* screen on */); 50 } 51 assertJobReady()52 void assertJobReady() throws Exception { 53 assertJobReady(STATE_JOB_ID); 54 } 55 assertJobWaiting()56 void assertJobWaiting() throws Exception { 57 assertJobWaiting(STATE_JOB_ID); 58 } 59 assertJobNotReady()60 void assertJobNotReady() throws Exception { 61 assertJobNotReady(STATE_JOB_ID); 62 } 63 waitFor(long waitMillis)64 static void waitFor(long waitMillis) throws Exception { 65 final long deadline = SystemClock.uptimeMillis() + waitMillis; 66 do { 67 Thread.sleep(500L); 68 } while (SystemClock.uptimeMillis() < deadline); 69 } 70 71 /** 72 * Toggle device is dock idle or dock active. 73 */ toggleFakeDeviceDockState(final boolean idle)74 private void toggleFakeDeviceDockState(final boolean idle) throws Exception { 75 mUiDevice.executeShellCommand("cmd jobscheduler trigger-dock-state " 76 + (idle ? "idle" : "active")); 77 // Wait a moment to let that happen before proceeding. 78 waitFor(2_000); 79 } 80 81 /** 82 * Make sure the screen state. 83 */ toggleScreenOn(final boolean screenon)84 private void toggleScreenOn(final boolean screenon) throws Exception { 85 if (screenon) { 86 mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); 87 } else { 88 mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); 89 } 90 // Since the screen on/off intent is ordered, they will not be sent right now. 91 waitFor(2_000); 92 } 93 94 /** 95 * Simulated for idle, and then perform idle maintenance now. 96 */ triggerIdleMaintenance()97 private void triggerIdleMaintenance() throws Exception { 98 mUiDevice.executeShellCommand("cmd activity idle-maintenance"); 99 // Wait a moment to let that happen before proceeding. 100 waitFor(2_000); 101 } 102 103 /** 104 * Schedule a job that requires the device is idle, and assert it fired to make 105 * sure the device is idle. 106 */ verifyIdleState()107 void verifyIdleState() throws Exception { 108 kTestEnvironment.setExpectedExecutions(1); 109 kTestEnvironment.setExpectedWaitForRun(); 110 mJobScheduler.schedule(mBuilder.setRequiresDeviceIdle(true).build()); 111 assertJobReady(); 112 kTestEnvironment.readyToRun(); 113 114 assertTrue("Job with idle constraint did not fire on idle", 115 kTestEnvironment.awaitExecution()); 116 } 117 118 /** 119 * Schedule a job that requires the device is idle, and assert it failed to make 120 * sure the device is active. 121 */ verifyActiveState()122 void verifyActiveState() throws Exception { 123 kTestEnvironment.setExpectedExecutions(0); 124 kTestEnvironment.setExpectedWaitForRun(); 125 mJobScheduler.schedule(mBuilder.setRequiresDeviceIdle(true).build()); 126 assertJobWaiting(); 127 assertJobNotReady(); 128 kTestEnvironment.readyToRun(); 129 130 assertFalse("Job with idle constraint fired while not on idle.", 131 kTestEnvironment.awaitExecution(250)); 132 } 133 134 /** 135 * Ensure that device can switch state normally. 136 */ testDeviceChangeIdleActiveState()137 public void testDeviceChangeIdleActiveState() throws Exception { 138 toggleScreenOn(true /* screen on */); 139 verifyActiveState(); 140 141 // Assert device is idle when screen is off for a while. 142 toggleScreenOn(false /* screen off */); 143 triggerIdleMaintenance(); 144 verifyIdleState(); 145 146 // Assert device is back to active when screen is on. 147 toggleScreenOn(true /* screen on */); 148 verifyActiveState(); 149 } 150 151 /** 152 * Check if dock state is supported. 153 */ isDockStateSupported()154 private boolean isDockStateSupported() { 155 // Car does not support dock state. 156 return !getContext().getPackageManager().hasSystemFeature( 157 PackageManager.FEATURE_AUTOMOTIVE); 158 } 159 160 /** 161 * Ensure that device can switch state on dock normally. 162 */ testScreenOnDeviceOnDockChangeState()163 public void testScreenOnDeviceOnDockChangeState() throws Exception { 164 if (!isDockStateSupported()) { 165 return; 166 } 167 toggleScreenOn(true /* screen on */); 168 verifyActiveState(); 169 170 // Assert device go to idle if user doesn't interact with device for a while. 171 toggleFakeDeviceDockState(true /* idle */); 172 triggerIdleMaintenance(); 173 verifyIdleState(); 174 175 // Assert device go back to active if user interacts with device. 176 toggleFakeDeviceDockState(false /* active */); 177 verifyActiveState(); 178 } 179 180 /** 181 * Ensure that ignores this dock intent during screen off. 182 */ testScreenOffDeviceOnDockNoChangeState()183 public void testScreenOffDeviceOnDockNoChangeState() throws Exception { 184 if (!isDockStateSupported()) { 185 return; 186 } 187 toggleScreenOn(false /* screen off */); 188 triggerIdleMaintenance(); 189 verifyIdleState(); 190 191 toggleFakeDeviceDockState(false /* active */); 192 verifyIdleState(); 193 } 194 } 195