1 /* 2 * Copyright (C) 2021 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.hardware.devicestate.cts; 18 19 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER; 20 import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE_IDENTIFIER; 21 import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE_IDENTIFIER; 22 import static android.server.wm.DeviceStateUtils.assertValidDeviceState; 23 import static android.server.wm.DeviceStateUtils.assertValidState; 24 import static android.server.wm.DeviceStateUtils.runWithControlDeviceStatePermission; 25 import static android.view.Display.DEFAULT_DISPLAY; 26 27 import static org.junit.Assert.assertEquals; 28 import static org.junit.Assert.assertFalse; 29 import static org.junit.Assert.assertTrue; 30 import static org.junit.Assume.assumeFalse; 31 import static org.junit.Assume.assumeTrue; 32 import static org.mockito.Mockito.atLeastOnce; 33 import static org.mockito.Mockito.mock; 34 import static org.mockito.Mockito.timeout; 35 import static org.mockito.Mockito.verify; 36 37 import android.hardware.devicestate.DeviceState; 38 import android.hardware.devicestate.DeviceStateManager; 39 import android.hardware.devicestate.DeviceStateRequest; 40 import android.util.ArraySet; 41 42 import androidx.annotation.NonNull; 43 import androidx.test.ext.junit.runners.AndroidJUnit4; 44 45 import com.android.compatibility.common.util.ApiTest; 46 import com.android.compatibility.common.util.PollingCheck; 47 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.mockito.ArgumentCaptor; 51 52 import java.util.HashSet; 53 import java.util.List; 54 import java.util.Set; 55 import java.util.concurrent.Executor; 56 57 /** CTS tests for {@link DeviceStateManager} API(s). */ 58 @RunWith(AndroidJUnit4.class) 59 public class DeviceStateManagerTests extends DeviceStateManagerTestBase { 60 61 public static final int TIMEOUT = 2000; 62 63 private static final int INVALID_DEVICE_STATE = -1; 64 65 /** 66 * Tests that {@link DeviceStateManager#getSupportedStates()} returns at least one state and 67 * that none of the returned states are in the range 68 * [{@link #MINIMUM_DEVICE_STATE_IDENTIFIER}, {@link #MAXIMUM_DEVICE_STATE_IDENTIFIER}]. 69 */ 70 @ApiTest(apis = { 71 "android.hardware.devicestate.DeviceStateManager#getSupportedStates", 72 "android.hardware.devicestate.DeviceStateManager#getSupportedDeviceStates", 73 "android.hardware.devicestate.DeviceState#getIdentifier", 74 "android.hardware.devicestate.DeviceState#getName"}) 75 @Test testValidSupportedStates()76 public void testValidSupportedStates() throws Exception { 77 final List<DeviceState> supportedDeviceStates = 78 getDeviceStateManager().getSupportedDeviceStates(); 79 80 for (DeviceState state: supportedDeviceStates) { 81 assertValidDeviceState(state); 82 } 83 } 84 85 /** 86 * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor, 87 * DeviceStateRequest.Callback)} is successful and results in a registered callback being 88 * triggered with a value equal to the requested state. 89 */ 90 @ApiTest(apis = { 91 "android.hardware.devicestate.DeviceStateManager#getSupportedDeviceStates", 92 "android.hardware.devicestate.DeviceStateManager#requestState", 93 "android.hardware.devicestate.DeviceState#getIdentifier"}) 94 @Test testRequestAllSupportedStates()95 public void testRequestAllSupportedStates() throws Throwable { 96 final ArgumentCaptor<DeviceState> intAgumentCaptor = ArgumentCaptor.forClass( 97 DeviceState.class); 98 final DeviceStateManager.DeviceStateCallback callback 99 = mock(DeviceStateManager.DeviceStateCallback.class); 100 final DeviceStateManager manager = getDeviceStateManager(); 101 manager.registerCallback(Runnable::run, callback); 102 103 final List<DeviceState> supportedStates = manager.getSupportedDeviceStates(); 104 for (int i = 0; i < supportedStates.size(); i++) { 105 final int stateToRequest = supportedStates.get(i).getIdentifier(); 106 final DeviceStateRequest request = 107 DeviceStateRequest.newBuilder(stateToRequest).build(); 108 109 runWithRequestActive(request, false, () -> { 110 verify(callback, atLeastOnce()).onDeviceStateChanged(intAgumentCaptor.capture()); 111 assertEquals(intAgumentCaptor.getValue().getIdentifier(), request.getState()); 112 }); 113 } 114 } 115 116 @ApiTest(apis = {"android.hardware.devicestate.DeviceStateManager#requestBaseStateOverride"}) 117 @Test testRequestBaseState()118 public void testRequestBaseState() throws Throwable { 119 final StateTrackingCallback callback = new StateTrackingCallback(); 120 final DeviceStateManager manager = getDeviceStateManager(); 121 122 manager.registerCallback(Runnable::run, callback); 123 124 DeviceStateRequest request = DeviceStateRequest.newBuilder(0).build(); 125 runWithRequestActive(request, true, () -> PollingCheck.waitFor(TIMEOUT, 126 () -> callback.mCurrentState.getIdentifier() == request.getState())); 127 } 128 129 /** 130 * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor, 131 * DeviceStateRequest.Callback)} throws an {@link java.lang.IllegalArgumentException} if 132 * supplied with a state above {@link MAXIMUM_DEVICE_STATE_IDENTIFIER}. 133 */ 134 @ApiTest(apis = {"android.hardware.devicestate.DeviceStateManager#requestState"}) 135 @Test(expected = IllegalArgumentException.class) testRequestStateTooLarge()136 public void testRequestStateTooLarge() throws Throwable { 137 final DeviceStateManager manager = getDeviceStateManager(); 138 final DeviceStateRequest request = 139 DeviceStateRequest.newBuilder(MAXIMUM_DEVICE_STATE_IDENTIFIER + 1).build(); 140 runWithControlDeviceStatePermission(() -> manager.requestState(request, null, null)); 141 } 142 143 /** 144 * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor, 145 * DeviceStateRequest.Callback)} throws an {@link java.lang.IllegalArgumentException} if 146 * supplied with a state below {@link MINIMUM_DEVICE_STATE_IDENTIFIER}. 147 */ 148 @ApiTest(apis = {"android.hardware.devicestate.DeviceStateManager#requestState"}) 149 @Test(expected = IllegalArgumentException.class) testRequestStateTooSmall()150 public void testRequestStateTooSmall() throws Throwable { 151 final DeviceStateManager manager = getDeviceStateManager(); 152 final DeviceStateRequest request = 153 DeviceStateRequest.newBuilder(MINIMUM_DEVICE_STATE_IDENTIFIER - 1).build(); 154 runWithControlDeviceStatePermission(() -> manager.requestState(request, null, null)); 155 } 156 157 /** 158 * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor, 159 * DeviceStateRequest.Callback)} is not successful and results in a failure to change the 160 * state of the device due to the state requested not being available for apps to request. 161 */ 162 @ApiTest(apis = { 163 "android.hardware.devicestate.DeviceStateManager#requestState", 164 "android.hardware.devicestate.DeviceState#hasProperty"}) 165 @Test testRequestStateFailsAsTopApp_ifStateNotDefinedAsAvailableForAppsToRequest()166 public void testRequestStateFailsAsTopApp_ifStateNotDefinedAsAvailableForAppsToRequest() 167 throws IllegalArgumentException { 168 final DeviceStateManager manager = getDeviceStateManager(); 169 final List<DeviceState> supportedStates = manager.getSupportedDeviceStates(); 170 // We want to verify that the app can change device state 171 // So we only attempt if there are more than 1 possible state. 172 assumeTrue(supportedStates.size() > 1); 173 Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(supportedStates); 174 // checks that not every state is available for an app to request 175 assumeTrue(statesAvailableToRequest.size() < supportedStates.size()); 176 177 Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates); 178 179 final StateTrackingCallback callback = new StateTrackingCallback(); 180 manager.registerCallback(Runnable::run, callback); 181 PollingCheck.waitFor(TIMEOUT, 182 () -> callback.mCurrentState.getIdentifier() != INVALID_DEVICE_STATE); 183 final TestActivitySession<DeviceStateTestActivity> activitySession = 184 createManagedTestActivitySession(); 185 186 activitySession.launchTestActivityOnDisplaySync( 187 DeviceStateTestActivity.class, 188 DEFAULT_DISPLAY 189 ); 190 191 DeviceStateTestActivity activity = activitySession.getActivity(); 192 193 Set<Integer> possibleStates = possibleStates(false /* shouldSucceed */, 194 availableDeviceStates, 195 statesAvailableToRequest); 196 int nextState = calculateDifferentState(callback.mCurrentState.getIdentifier(), 197 possibleStates); 198 // checks that we were able to find a valid state to request. 199 assumeTrue(nextState != INVALID_DEVICE_STATE); 200 201 activity.requestDeviceStateChange(nextState); 202 203 assertTrue(activity.requestStateFailed); 204 } 205 206 /** 207 * Tests that calling {@link DeviceStateManager#requestState(DeviceStateRequest, Executor, 208 * DeviceStateRequest.Callback)} is successful and results in a registered callback being 209 * triggered with a value equal to the requested state. 210 */ 211 @ApiTest(apis = { 212 "android.hardware.devicestate.DeviceStateManager#requestState", 213 "android.hardware.devicestate.DeviceStateManager#cancelStateRequest", 214 "android.hardware.devicestate.DeviceState#hasProperty", 215 "android.hardware.devicestate.DeviceState#getIdentifier"}) 216 @Test testRequestStateSucceedsAsTopApp_ifStateDefinedAsAvailableForAppsToRequest()217 public void testRequestStateSucceedsAsTopApp_ifStateDefinedAsAvailableForAppsToRequest() 218 throws Throwable { 219 final DeviceStateManager manager = getDeviceStateManager(); 220 final List<DeviceState> supportedStates = manager.getSupportedDeviceStates(); 221 222 // We want to verify that the app can change device state 223 // So we only attempt if there are more than 1 possible state. 224 assumeTrue(supportedStates.size() > 1); 225 final Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(supportedStates); 226 assumeFalse(statesAvailableToRequest.isEmpty()); 227 228 final Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates); 229 230 final StateTrackingCallback callback = new StateTrackingCallback(); 231 manager.registerCallback(Runnable::run, callback); 232 PollingCheck.waitFor(TIMEOUT, 233 () -> callback.mCurrentState.getIdentifier() != INVALID_DEVICE_STATE); 234 final TestActivitySession<DeviceStateTestActivity> activitySession = 235 createManagedTestActivitySession(); 236 237 activitySession.launchTestActivityOnDisplaySync( 238 DeviceStateTestActivity.class, 239 DEFAULT_DISPLAY 240 ); 241 242 final DeviceStateTestActivity activity = activitySession.getActivity(); 243 244 final Set<Integer> possibleStates = possibleStates(true /* shouldSucceed */, 245 availableDeviceStates, 246 statesAvailableToRequest); 247 int nextState = calculateDifferentState(callback.mCurrentState.getIdentifier(), 248 possibleStates); 249 // checks that we were able to find a valid state to request. 250 assumeTrue(nextState != INVALID_DEVICE_STATE); 251 252 runWithControlDeviceStatePermission(() -> activity.requestDeviceStateChange(nextState)); 253 254 // We have to check the state has transitioned first, before checking to verify the activity 255 // has been made visible again. 256 PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState.getIdentifier() == nextState); 257 PollingCheck.waitFor(TIMEOUT, () -> activity.mResumed); 258 259 assertEquals(nextState, callback.mCurrentState.getIdentifier()); 260 assertFalse(activity.requestStateFailed); 261 262 manager.cancelStateRequest(); // reset device state after successful request 263 } 264 265 /** 266 * Tests that calling {@link DeviceStateManager#requestState} is unsuccessful and results in a 267 * failure to update the state of the device as expected since the activity is backgrounded. 268 */ 269 @ApiTest(apis = { 270 "android.hardware.devicestate.DeviceStateManager#requestState", 271 "android.hardware.devidestate.DeviceState#hasProperty" }) 272 @Test testRequestStateFailsAsBackgroundApp()273 public void testRequestStateFailsAsBackgroundApp() throws IllegalArgumentException { 274 final DeviceStateManager manager = getDeviceStateManager(); 275 final List<DeviceState> supportedStates = manager.getSupportedDeviceStates(); 276 // We want to verify that the app can change device state 277 // So we only attempt if there are more than 1 possible state. 278 assumeTrue(supportedStates.size() > 1); 279 final Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(supportedStates); 280 assumeFalse(statesAvailableToRequest.isEmpty()); 281 282 final Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates); 283 284 final StateTrackingCallback callback = new StateTrackingCallback(); 285 manager.registerCallback(Runnable::run, callback); 286 PollingCheck.waitFor(TIMEOUT, 287 () -> callback.mCurrentState.getIdentifier() != INVALID_DEVICE_STATE); 288 289 final TestActivitySession<DeviceStateTestActivity> activitySession = 290 createManagedTestActivitySession(); 291 activitySession.launchTestActivityOnDisplaySync( 292 DeviceStateTestActivity.class, 293 DEFAULT_DISPLAY 294 ); 295 296 final DeviceStateTestActivity activity = activitySession.getActivity(); 297 assertFalse(activity.requestStateFailed); 298 299 launchHomeActivity(); // places our test activity in the background 300 301 final Set<Integer> possibleStates = possibleStates(true /* shouldSucceed */, 302 availableDeviceStates, 303 statesAvailableToRequest); 304 int nextState = calculateDifferentState(callback.mCurrentState.getIdentifier(), 305 possibleStates); 306 // checks that we were able to find a valid state to request. 307 assumeTrue(nextState != INVALID_DEVICE_STATE); 308 309 activity.requestDeviceStateChange(nextState); 310 311 assertTrue(activity.requestStateFailed); 312 } 313 314 /** 315 * Tests that calling {@link DeviceStateManager#cancelStateRequest} is successful and results 316 * in a registered callback being triggered with a value equal to the base state. 317 */ 318 @ApiTest(apis = {"android.hardware.devicestate.DeviceStateManager#cancelStateRequest"}) 319 @Test testCancelStateRequestFromNewActivity()320 public void testCancelStateRequestFromNewActivity() throws Throwable { 321 final DeviceStateManager manager = getDeviceStateManager(); 322 final List<DeviceState> supportedStates = manager.getSupportedDeviceStates(); 323 // We want to verify that the app can change device state 324 // So we only attempt if there are more than 1 possible state. 325 assumeTrue(supportedStates.size() > 1); 326 final Set<Integer> statesAvailableToRequest = getAvailableStatesToRequest(supportedStates); 327 assumeFalse(statesAvailableToRequest.isEmpty()); 328 329 final Set<Integer> availableDeviceStates = generateDeviceStateSet(supportedStates); 330 331 final StateTrackingCallback callback = new StateTrackingCallback(); 332 manager.registerCallback(Runnable::run, callback); 333 PollingCheck.waitFor(TIMEOUT, 334 () -> callback.mCurrentState.getIdentifier() != INVALID_DEVICE_STATE); 335 final TestActivitySession<DeviceStateTestActivity> activitySession = 336 createManagedTestActivitySession(); 337 338 activitySession.launchTestActivityOnDisplaySync( 339 DeviceStateTestActivity.class, 340 DEFAULT_DISPLAY 341 ); 342 343 final DeviceStateTestActivity activity = activitySession.getActivity(); 344 345 int originalState = callback.mCurrentState.getIdentifier(); 346 347 final Set<Integer> possibleStates = possibleStates(true /* shouldSucceed */, 348 availableDeviceStates, 349 statesAvailableToRequest); 350 int nextState = calculateDifferentState(callback.mCurrentState.getIdentifier(), 351 possibleStates); 352 // checks that we were able to find a valid state to request. 353 assumeTrue(nextState != INVALID_DEVICE_STATE); 354 355 runWithControlDeviceStatePermission(() -> activity.requestDeviceStateChange(nextState)); 356 357 PollingCheck.waitFor(TIMEOUT, () -> callback.mCurrentState.getIdentifier() == nextState); 358 359 assertEquals(nextState, callback.mCurrentState.getIdentifier()); 360 assertFalse(activity.requestStateFailed); 361 362 activity.finish(); 363 364 final TestActivitySession<DeviceStateTestActivity> secondActivitySession = 365 createManagedTestActivitySession(); 366 secondActivitySession.launchTestActivityOnDisplaySync( 367 DeviceStateTestActivity.class, 368 DEFAULT_DISPLAY 369 ); 370 // Assumes that the overridden state is still active after finishing 371 // and launching the second activity. This due to some states may be cancelled 372 // if they have the FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP flag on them. 373 // TODO(b/305107721): Update this call when we can verify we're moving to a state 374 // that does not have the FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP flag. 375 assumeTrue(nextState == callback.mCurrentState.getIdentifier()); 376 377 final DeviceStateTestActivity activity2 = secondActivitySession.getActivity(); 378 activity2.cancelOverriddenState(); 379 380 PollingCheck.waitFor(TIMEOUT, 381 () -> callback.mCurrentState.getIdentifier() == originalState); 382 383 assertEquals(originalState, callback.mCurrentState.getIdentifier()); 384 } 385 386 387 /** 388 * Returns a set of device states that are available to be requested by an application. 389 * 390 * @param supportedStates The device states that are supported on that device. 391 * @return {@link Set} of valid device states that are read in. 392 */ getAvailableStatesToRequest(List<DeviceState> supportedStates)393 private static Set<Integer> getAvailableStatesToRequest(List<DeviceState> supportedStates) { 394 final Set<Integer> availableStatesToRequest = new HashSet<>(); 395 for (DeviceState state : supportedStates) { 396 if (state.hasProperty(DeviceState.PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST)) { 397 availableStatesToRequest.add(state.getIdentifier()); 398 } 399 } 400 return availableStatesToRequest; 401 } 402 403 /** 404 * Generates a set of possible device states based on a {@link Set} of valid device states, 405 * {@code supportedDeviceStates}, and the set of device states available to be requested 406 * {@code availableStatesToRequest}, as well as if the request should succeed or not, given by 407 * {@code shouldSucceed}. 408 * 409 * If {@code shouldSucceed} is {@code true}, we only return device states that are available, 410 * and if it is {@code false}, we only return non available device states. 411 * 412 * @param availableStatesToRequest The states that are available to be requested from an app 413 * @param shouldSucceed Should the request succeed or not, to determine what states 414 * we return 415 * @param supportedDeviceStates All states supported on the device. 416 * {@throws} an {@link IllegalArgumentException} if 417 * {@code availableStatesToRequest} includes 418 * non-valid device states. 419 */ possibleStates(boolean shouldSucceed, Set<Integer> supportedDeviceStates, Set<Integer> availableStatesToRequest)420 private static Set<Integer> possibleStates(boolean shouldSucceed, 421 Set<Integer> supportedDeviceStates, 422 Set<Integer> availableStatesToRequest) { 423 424 if (!supportedDeviceStates.containsAll(availableStatesToRequest)) { 425 throw new IllegalArgumentException("Available states include invalid device states"); 426 } 427 428 final Set<Integer> availableStates = new HashSet<>(supportedDeviceStates); 429 430 if (shouldSucceed) { 431 availableStates.retainAll(availableStatesToRequest); 432 } else { 433 availableStates.removeAll(availableStatesToRequest); 434 } 435 436 return availableStates; 437 } 438 439 /** 440 * Determines what state we should request that isn't the current state, and is included 441 * in {@code possibleStates}. If there is no state that fits these requirements, we return 442 * {@link INVALID_DEVICE_STATE}. 443 * 444 * @param currentState The current state of the device 445 * @param possibleStates States that we can request 446 */ calculateDifferentState(int currentState, Set<Integer> possibleStates)447 private static int calculateDifferentState(int currentState, Set<Integer> possibleStates) { 448 if (possibleStates.isEmpty()) { 449 return INVALID_DEVICE_STATE; 450 } 451 if (possibleStates.size() == 1 && possibleStates.contains(currentState)) { 452 return INVALID_DEVICE_STATE; 453 } 454 for (int state : possibleStates) { 455 if (state != currentState) { 456 return state; 457 } 458 } 459 return INVALID_DEVICE_STATE; 460 } 461 462 /** 463 * Creates a {@link Set} of values that are in the {@code states} array. 464 * 465 * Used to create a {@link Set} from the available device states that {@link DeviceStateManager} 466 * returns as an array. 467 * 468 * @param states Device states that are supported on the device 469 */ generateDeviceStateSet(List<DeviceState> states)470 private static Set<Integer> generateDeviceStateSet(List<DeviceState> states) { 471 Set<Integer> supportedStates = new ArraySet<>(); 472 for (DeviceState state: states) { 473 supportedStates.add(state.getIdentifier()); 474 } 475 return supportedStates; 476 } 477 478 /** 479 * Tests that calling {@link DeviceStateManager#requestState()} throws a 480 * {@link java.lang.SecurityException} without the 481 * {@link android.Manifest.permission.CONTROL_DEVICE_STATE} permission held. 482 */ 483 @Test(expected = SecurityException.class) 484 @ApiTest(apis = {"android.hardware.devicestate.DeviceStateManager#requestState"}) testRequestStateWithoutPermission()485 public void testRequestStateWithoutPermission() { 486 final DeviceStateManager manager = getDeviceStateManager(); 487 final List<DeviceState> states = manager.getSupportedDeviceStates(); 488 final DeviceStateRequest request = DeviceStateRequest.newBuilder( 489 states.get(0).getIdentifier()).build(); 490 manager.requestState(request, null, null); 491 } 492 493 /** 494 * Tests that calling {@link DeviceStateManager#cancelStateRequest} throws a 495 * {@link java.lang.SecurityException} without the 496 * {@link android.Manifest.permission.CONTROL_DEVICE_STATE} permission held. 497 */ 498 @ApiTest(apis = {"android.hardware.devicestate.DeviceStateManager#cancelStateRequest"}) 499 @Test(expected = SecurityException.class) testCancelOverrideRequestWithoutPermission()500 public void testCancelOverrideRequestWithoutPermission() throws Throwable { 501 final DeviceStateManager manager = getDeviceStateManager(); 502 final List<DeviceState> states = manager.getSupportedDeviceStates(); 503 final DeviceStateRequest request = DeviceStateRequest.newBuilder( 504 states.get(0).getIdentifier()).build(); 505 runWithRequestActive(request, false, manager::cancelStateRequest); 506 } 507 508 /** 509 * Tests that callbacks added with {@link DeviceStateManager#registerDeviceStateCallback()} are 510 * supplied with an initial callback that contains the state at the time of registration. 511 */ 512 @ApiTest(apis = {"android.hardware.devicestate.DeviceStateManager#registerCallback"}) 513 @Test testRegisterCallbackSuppliesInitialValue()514 public void testRegisterCallbackSuppliesInitialValue() throws InterruptedException { 515 final ArgumentCaptor<List<DeviceState>> deviceStateListAgumentCaptor = 516 ArgumentCaptor.forClass(List.class); 517 final ArgumentCaptor<DeviceState> deviceStateAgumentCaptor = ArgumentCaptor.forClass( 518 DeviceState.class); 519 520 final DeviceStateManager.DeviceStateCallback callback 521 = mock(DeviceStateManager.DeviceStateCallback.class); 522 final DeviceStateManager manager = getDeviceStateManager(); 523 manager.registerCallback(Runnable::run, callback); 524 525 verify(callback, timeout(CALLBACK_TIMEOUT_MS)).onDeviceStateChanged( 526 deviceStateAgumentCaptor.capture()); 527 assertValidState(deviceStateAgumentCaptor.getValue().getIdentifier()); 528 529 verify(callback, timeout(CALLBACK_TIMEOUT_MS)) 530 .onSupportedStatesChanged(deviceStateListAgumentCaptor.capture()); 531 final List<DeviceState> supportedStates = deviceStateListAgumentCaptor.getValue(); 532 assertFalse(supportedStates.isEmpty()); 533 for (int i = 0; i < supportedStates.size(); i++) { 534 final int state = supportedStates.get(i).getIdentifier(); 535 assertValidState(state); 536 } 537 } 538 539 private static class StateTrackingCallback implements DeviceStateManager.DeviceStateCallback { 540 private DeviceState mCurrentState = new DeviceState( 541 new DeviceState.Configuration.Builder(INVALID_DEVICE_STATE_IDENTIFIER, 542 "" /* name */).build()); 543 544 @Override onDeviceStateChanged(@onNull DeviceState state)545 public void onDeviceStateChanged(@NonNull DeviceState state) { 546 mCurrentState = state; 547 } 548 } 549 } 550