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