1 /* 2 * Copyright (C) 2020 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.server.policy; 18 19 20 import static android.content.Context.SENSOR_SERVICE; 21 22 import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED; 23 import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED; 24 import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED; 25 import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL; 26 import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL; 27 import static com.android.server.policy.DeviceStateProviderImpl.DEFAULT_DEVICE_STATE; 28 29 import static org.junit.Assert.assertArrayEquals; 30 import static org.junit.Assert.assertEquals; 31 import static org.mockito.ArgumentMatchers.anyInt; 32 import static org.mockito.Mockito.eq; 33 import static org.mockito.Mockito.mock; 34 import static org.mockito.Mockito.never; 35 import static org.mockito.Mockito.verify; 36 import static org.mockito.Mockito.when; 37 38 import android.annotation.Nullable; 39 import android.content.Context; 40 import android.hardware.Sensor; 41 import android.hardware.SensorEvent; 42 import android.hardware.SensorManager; 43 import android.os.PowerManager; 44 45 import androidx.annotation.NonNull; 46 47 import com.android.server.LocalServices; 48 import com.android.server.devicestate.DeviceState; 49 import com.android.server.devicestate.DeviceStateProvider; 50 import com.android.server.input.InputManagerInternal; 51 52 import org.junit.After; 53 import org.junit.Before; 54 import org.junit.Test; 55 import org.mockito.ArgumentCaptor; 56 import org.mockito.Mockito; 57 import org.mockito.internal.util.reflection.FieldSetter; 58 59 import java.io.ByteArrayInputStream; 60 import java.io.IOException; 61 import java.io.InputStream; 62 import java.lang.reflect.Constructor; 63 import java.util.List; 64 65 /** 66 * Unit tests for {@link DeviceStateProviderImpl}. 67 * <p/> 68 * Run with <code>atest DeviceStateProviderImplTest</code>. 69 */ 70 public final class DeviceStateProviderImplTest { 71 private final ArgumentCaptor<DeviceState[]> mDeviceStateArrayCaptor = ArgumentCaptor.forClass( 72 DeviceState[].class); 73 private final ArgumentCaptor<Integer> mIntegerCaptor = ArgumentCaptor.forClass(Integer.class); 74 private static final int MAX_HINGE_ANGLE_EXCLUSIVE = 360; 75 76 private Context mContext; 77 private SensorManager mSensorManager; 78 79 @Before setup()80 public void setup() { 81 LocalServices.addService(InputManagerInternal.class, mock(InputManagerInternal.class)); 82 mContext = mock(Context.class); 83 mSensorManager = mock(SensorManager.class); 84 when(mContext.getSystemServiceName(eq(SensorManager.class))).thenReturn(SENSOR_SERVICE); 85 when(mContext.getSystemService(eq(SENSOR_SERVICE))).thenReturn(mSensorManager); 86 } 87 88 @After tearDown()89 public void tearDown() { 90 LocalServices.removeServiceForTest(InputManagerInternal.class); 91 } 92 93 @Test create_noConfig()94 public void create_noConfig() { 95 assertDefaultProviderValues(null); 96 } 97 98 @Test create_emptyFile()99 public void create_emptyFile() { 100 String configString = ""; 101 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 102 103 assertDefaultProviderValues(config); 104 } 105 106 @Test create_emptyConfig()107 public void create_emptyConfig() { 108 String configString = "<device-state-config></device-state-config>"; 109 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 110 111 assertDefaultProviderValues(config); 112 } 113 114 @Test create_invalidConfig()115 public void create_invalidConfig() { 116 String configString = "<device-state-config>\n" 117 + " </device-state>\n" 118 + "</device-state-config>\n"; 119 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 120 121 assertDefaultProviderValues(config); 122 } 123 assertDefaultProviderValues( @ullable DeviceStateProviderImpl.ReadableConfig config)124 private void assertDefaultProviderValues( 125 @Nullable DeviceStateProviderImpl.ReadableConfig config) { 126 DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext, 127 config); 128 129 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 130 provider.setListener(listener); 131 132 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 133 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 134 assertArrayEquals(new DeviceState[]{DEFAULT_DEVICE_STATE}, 135 mDeviceStateArrayCaptor.getValue()); 136 137 verify(listener).onStateChanged(mIntegerCaptor.capture()); 138 assertEquals(DEFAULT_DEVICE_STATE.getIdentifier(), mIntegerCaptor.getValue().intValue()); 139 } 140 141 @Test create_multipleMatchingStatesDefaultsToLowestIdentifier()142 public void create_multipleMatchingStatesDefaultsToLowestIdentifier() { 143 String configString = "<device-state-config>\n" 144 + " <device-state>\n" 145 + " <identifier>1</identifier>\n" 146 + " <conditions/>\n" 147 + " </device-state>\n" 148 + " <device-state>\n" 149 + " <identifier>2</identifier>\n" 150 + " <conditions/>\n" 151 + " </device-state>\n" 152 + "</device-state-config>\n"; 153 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 154 DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext, 155 config); 156 157 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 158 provider.setListener(listener); 159 160 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 161 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 162 final DeviceState[] expectedStates = new DeviceState[]{ 163 new DeviceState(1, "", 0 /* flags */), 164 new DeviceState(2, "", 0 /* flags */) }; 165 assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue()); 166 167 verify(listener).onStateChanged(mIntegerCaptor.capture()); 168 assertEquals(1, mIntegerCaptor.getValue().intValue()); 169 } 170 171 @Test create_stateWithCancelOverrideRequestFlag()172 public void create_stateWithCancelOverrideRequestFlag() { 173 String configString = "<device-state-config>\n" 174 + " <device-state>\n" 175 + " <identifier>1</identifier>\n" 176 + " <flags>\n" 177 + " <flag>FLAG_CANCEL_OVERRIDE_REQUESTS</flag>\n" 178 + " </flags>\n" 179 + " <conditions/>\n" 180 + " </device-state>\n" 181 + " <device-state>\n" 182 + " <identifier>2</identifier>\n" 183 + " <conditions/>\n" 184 + " </device-state>\n" 185 + "</device-state-config>\n"; 186 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 187 DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext, 188 config); 189 190 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 191 provider.setListener(listener); 192 193 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 194 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 195 final DeviceState[] expectedStates = new DeviceState[]{ 196 new DeviceState(1, "", DeviceState.FLAG_CANCEL_OVERRIDE_REQUESTS), 197 new DeviceState(2, "", 0 /* flags */) }; 198 assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue()); 199 } 200 201 @Test create_stateWithInvalidFlag()202 public void create_stateWithInvalidFlag() { 203 String configString = "<device-state-config>\n" 204 + " <device-state>\n" 205 + " <identifier>1</identifier>\n" 206 + " <flags>\n" 207 + " <flag>INVALID_FLAG</flag>\n" 208 + " </flags>\n" 209 + " <conditions/>\n" 210 + " </device-state>\n" 211 + " <device-state>\n" 212 + " <identifier>2</identifier>\n" 213 + " <conditions/>\n" 214 + " </device-state>\n" 215 + "</device-state-config>\n"; 216 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 217 DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext, 218 config); 219 220 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 221 provider.setListener(listener); 222 223 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 224 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 225 final DeviceState[] expectedStates = new DeviceState[]{ 226 new DeviceState(1, "", 0 /* flags */), 227 new DeviceState(2, "", 0 /* flags */) }; 228 assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue()); 229 } 230 231 @Test create_lidSwitch()232 public void create_lidSwitch() { 233 String configString = "<device-state-config>\n" 234 + " <device-state>\n" 235 + " <identifier>1</identifier>\n" 236 + " <conditions>\n" 237 + " <lid-switch>\n" 238 + " <open>true</open>\n" 239 + " </lid-switch>\n" 240 + " </conditions>\n" 241 + " </device-state>\n" 242 + " <device-state>\n" 243 + " <identifier>2</identifier>\n" 244 + " <name>CLOSED</name>\n" 245 + " <conditions>\n" 246 + " <lid-switch>\n" 247 + " <open>false</open>\n" 248 + " </lid-switch>\n" 249 + " </conditions>\n" 250 + " </device-state>\n" 251 + "</device-state-config>\n"; 252 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 253 DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext, 254 config); 255 256 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 257 provider.setListener(listener); 258 259 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 260 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 261 final DeviceState[] expectedStates = new DeviceState[]{ 262 new DeviceState(1, "", 0 /* flags */), 263 new DeviceState(2, "CLOSED", 0 /* flags */) }; 264 assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue()); 265 266 // onStateChanged() should not be called because the provider has not yet been notified of 267 // the initial lid switch state. 268 verify(listener, never()).onStateChanged(mIntegerCaptor.capture()); 269 270 provider.notifyLidSwitchChanged(0, false /* lidOpen */); 271 272 verify(listener).onStateChanged(mIntegerCaptor.capture()); 273 assertEquals(2, mIntegerCaptor.getValue().intValue()); 274 275 Mockito.clearInvocations(listener); 276 277 provider.notifyLidSwitchChanged(1, true /* lidOpen */); 278 verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 279 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 280 verify(listener).onStateChanged(mIntegerCaptor.capture()); 281 assertEquals(1, mIntegerCaptor.getValue().intValue()); 282 } 283 create_sensorBasedProvider(Sensor sensor)284 private DeviceStateProviderImpl create_sensorBasedProvider(Sensor sensor) { 285 String configString = "<device-state-config>\n" 286 + " <device-state>\n" 287 + " <identifier>1</identifier>\n" 288 + " <name>CLOSED</name>\n" 289 + " <conditions>\n" 290 + " <sensor>\n" 291 + " <type>" + sensor.getStringType() + "</type>\n" 292 + " <name>" + sensor.getName() + "</name>\n" 293 + " <value>\n" 294 + " <max>90</max>\n" 295 + " </value>\n" 296 + " </sensor>\n" 297 + " </conditions>\n" 298 + " </device-state>\n" 299 + " <device-state>\n" 300 + " <identifier>2</identifier>\n" 301 + " <name>HALF_OPENED</name>\n" 302 + " <conditions>\n" 303 + " <sensor>\n" 304 + " <type>" + sensor.getStringType() + "</type>\n" 305 + " <name>" + sensor.getName() + "</name>\n" 306 + " <value>\n" 307 + " <min-inclusive>90</min-inclusive>\n" 308 + " <max>180</max>\n" 309 + " </value>\n" 310 + " </sensor>\n" 311 + " </conditions>\n" 312 + " </device-state>\n" 313 + " <device-state>\n" 314 + " <identifier>3</identifier>\n" 315 + " <name>OPENED</name>\n" 316 + " <conditions>\n" 317 + " <sensor>\n" 318 + " <type>" + sensor.getStringType() + "</type>\n" 319 + " <name>" + sensor.getName() + "</name>\n" 320 + " <value>\n" 321 + " <min-inclusive>180</min-inclusive>\n" 322 + " <max>" + MAX_HINGE_ANGLE_EXCLUSIVE + "</max>\n" 323 + " </value>\n" 324 + " </sensor>\n" 325 + " </conditions>\n" 326 + " </device-state>\n" 327 + " <device-state>\n" 328 + " <identifier>4</identifier>\n" 329 + " <name>THERMAL_TEST</name>\n" 330 + " <flags>\n" 331 + " <flag>FLAG_EMULATED_ONLY</flag>\n" 332 + " <flag>FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL</flag>\n" 333 + " <flag>FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE</flag>\n" 334 + " </flags>\n" 335 + " </device-state>\n" 336 + "</device-state-config>\n"; 337 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 338 return DeviceStateProviderImpl.createFromConfig(mContext, 339 config); 340 } 341 342 @Test create_sensor()343 public void create_sensor() throws Exception { 344 Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE); 345 when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of(sensor)); 346 DeviceStateProviderImpl provider = create_sensorBasedProvider(sensor); 347 348 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 349 provider.setListener(listener); 350 351 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 352 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 353 assertArrayEquals( 354 new DeviceState[]{ 355 new DeviceState(1, "CLOSED", 0 /* flags */), 356 new DeviceState(2, "HALF_OPENED", 0 /* flags */), 357 new DeviceState(3, "OPENED", 0 /* flags */), 358 new DeviceState(4, "THERMAL_TEST", 359 DeviceState.FLAG_EMULATED_ONLY 360 | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL 361 | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) }, 362 mDeviceStateArrayCaptor.getValue()); 363 // onStateChanged() should not be called because the provider has not yet been notified of 364 // the initial sensor state. 365 verify(listener, never()).onStateChanged(mIntegerCaptor.capture()); 366 367 Mockito.clearInvocations(listener); 368 369 SensorEvent event0 = mock(SensorEvent.class); 370 event0.sensor = sensor; 371 FieldSetter.setField(event0, event0.getClass().getField("values"), new float[]{180}); 372 373 provider.onSensorChanged(event0); 374 375 verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 376 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 377 verify(listener).onStateChanged(mIntegerCaptor.capture()); 378 assertEquals(3, mIntegerCaptor.getValue().intValue()); 379 380 Mockito.clearInvocations(listener); 381 382 SensorEvent event1 = mock(SensorEvent.class); 383 event1.sensor = sensor; 384 FieldSetter.setField(event1, event1.getClass().getField("values"), new float[]{90}); 385 386 provider.onSensorChanged(event1); 387 388 verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 389 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 390 verify(listener).onStateChanged(mIntegerCaptor.capture()); 391 assertEquals(2, mIntegerCaptor.getValue().intValue()); 392 393 Mockito.clearInvocations(listener); 394 395 SensorEvent event2 = mock(SensorEvent.class); 396 event2.sensor = sensor; 397 FieldSetter.setField(event2, event2.getClass().getField("values"), new float[]{0}); 398 399 provider.onSensorChanged(event2); 400 401 verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 402 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 403 verify(listener).onStateChanged(mIntegerCaptor.capture()); 404 assertEquals(1, mIntegerCaptor.getValue().intValue()); 405 } 406 407 @Test test_flagDisableWhenThermalStatusCritical()408 public void test_flagDisableWhenThermalStatusCritical() throws Exception { 409 Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE); 410 when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of(sensor)); 411 DeviceStateProviderImpl provider = create_sensorBasedProvider(sensor); 412 413 provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_LIGHT); 414 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 415 provider.setListener(listener); 416 417 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 418 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 419 assertArrayEquals( 420 new DeviceState[]{ 421 new DeviceState(1, "CLOSED", 0 /* flags */), 422 new DeviceState(2, "HALF_OPENED", 0 /* flags */), 423 new DeviceState(3, "OPENED", 0 /* flags */), 424 new DeviceState(4, "THERMAL_TEST", 425 DeviceState.FLAG_EMULATED_ONLY 426 | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL 427 | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) }, 428 mDeviceStateArrayCaptor.getValue()); 429 Mockito.clearInvocations(listener); 430 431 provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_MODERATE); 432 verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 433 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 434 Mockito.clearInvocations(listener); 435 436 // The THERMAL_TEST state should be disabled. 437 provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_CRITICAL); 438 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 439 eq(SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL)); 440 assertArrayEquals( 441 new DeviceState[]{ 442 new DeviceState(1, "CLOSED", 0 /* flags */), 443 new DeviceState(2, "HALF_OPENED", 0 /* flags */), 444 new DeviceState(3, "OPENED", 0 /* flags */) }, 445 mDeviceStateArrayCaptor.getValue()); 446 Mockito.clearInvocations(listener); 447 448 // The THERMAL_TEST state should be re-enabled. 449 provider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_LIGHT); 450 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 451 eq(SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL)); 452 assertArrayEquals( 453 new DeviceState[]{ 454 new DeviceState(1, "CLOSED", 0 /* flags */), 455 new DeviceState(2, "HALF_OPENED", 0 /* flags */), 456 new DeviceState(3, "OPENED", 0 /* flags */), 457 new DeviceState(4, "THERMAL_TEST", 458 DeviceState.FLAG_EMULATED_ONLY 459 | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL 460 | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) }, 461 mDeviceStateArrayCaptor.getValue()); 462 } 463 464 @Test test_flagDisableWhenPowerSaveEnabled()465 public void test_flagDisableWhenPowerSaveEnabled() throws Exception { 466 Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE); 467 when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of(sensor)); 468 DeviceStateProviderImpl provider = create_sensorBasedProvider(sensor); 469 470 provider.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */); 471 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 472 provider.setListener(listener); 473 474 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 475 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 476 assertArrayEquals( 477 new DeviceState[]{ 478 new DeviceState(1, "CLOSED", 0 /* flags */), 479 new DeviceState(2, "HALF_OPENED", 0 /* flags */), 480 new DeviceState(3, "OPENED", 0 /* flags */), 481 new DeviceState(4, "THERMAL_TEST", 482 DeviceState.FLAG_EMULATED_ONLY 483 | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL 484 | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) }, 485 mDeviceStateArrayCaptor.getValue()); 486 Mockito.clearInvocations(listener); 487 488 provider.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */); 489 verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 490 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 491 Mockito.clearInvocations(listener); 492 493 // The THERMAL_TEST state should be disabled due to power save being enabled. 494 provider.onPowerSaveModeChanged(true /* isPowerSaveModeEnabled */); 495 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 496 eq(SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED)); 497 assertArrayEquals( 498 new DeviceState[]{ 499 new DeviceState(1, "CLOSED", 0 /* flags */), 500 new DeviceState(2, "HALF_OPENED", 0 /* flags */), 501 new DeviceState(3, "OPENED", 0 /* flags */) }, 502 mDeviceStateArrayCaptor.getValue()); 503 Mockito.clearInvocations(listener); 504 505 // The THERMAL_TEST state should be re-enabled. 506 provider.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */); 507 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 508 eq(SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED)); 509 assertArrayEquals( 510 new DeviceState[]{ 511 new DeviceState(1, "CLOSED", 0 /* flags */), 512 new DeviceState(2, "HALF_OPENED", 0 /* flags */), 513 new DeviceState(3, "OPENED", 0 /* flags */), 514 new DeviceState(4, "THERMAL_TEST", 515 DeviceState.FLAG_EMULATED_ONLY 516 | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL 517 | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) }, 518 mDeviceStateArrayCaptor.getValue()); 519 } 520 521 @Test test_invalidSensorValues()522 public void test_invalidSensorValues() throws Exception { 523 // onStateChanged() should not be triggered by invalid sensor values. 524 525 Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE); 526 when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of(sensor)); 527 DeviceStateProviderImpl provider = create_sensorBasedProvider(sensor); 528 529 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 530 provider.setListener(listener); 531 Mockito.clearInvocations(listener); 532 533 // First, switch to a non-default state. 534 SensorEvent event1 = mock(SensorEvent.class); 535 event1.sensor = sensor; 536 FieldSetter.setField(event1, event1.getClass().getField("values"), new float[]{90}); 537 provider.onSensorChanged(event1); 538 verify(listener).onStateChanged(mIntegerCaptor.capture()); 539 assertEquals(2, mIntegerCaptor.getValue().intValue()); 540 541 Mockito.clearInvocations(listener); 542 543 // Then, send an invalid sensor event, verify that onStateChanged() is not triggered. 544 SensorEvent event2 = mock(SensorEvent.class); 545 event2.sensor = sensor; 546 FieldSetter.setField(event2, event2.getClass().getField("values"), 547 new float[]{MAX_HINGE_ANGLE_EXCLUSIVE}); 548 549 provider.onSensorChanged(event2); 550 551 verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 552 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 553 verify(listener, never()).onStateChanged(mIntegerCaptor.capture()); 554 } 555 556 @Test create_invalidSensor()557 public void create_invalidSensor() throws Exception { 558 Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE); 559 when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of()); 560 561 String configString = "<device-state-config>\n" 562 + " <device-state>\n" 563 + " <identifier>1</identifier>\n" 564 + " <name>CLOSED</name>\n" 565 + " <conditions>\n" 566 + " <sensor>\n" 567 + " <type>" + sensor.getStringType() + "</type>\n" 568 + " <name>" + sensor.getName() + "</name>\n" 569 + " <value>\n" 570 + " <max>90</max>\n" 571 + " </value>\n" 572 + " </sensor>\n" 573 + " </conditions>\n" 574 + " </device-state>\n" 575 + " <device-state>\n" 576 + " <identifier>2</identifier>\n" 577 + " <name>HALF_OPENED</name>\n" 578 + " <conditions>\n" 579 + " <sensor>\n" 580 + " <type>" + sensor.getStringType() + "</type>\n" 581 + " <name>" + sensor.getName() + "</name>\n" 582 + " <value>\n" 583 + " <min-inclusive>90</min-inclusive>\n" 584 + " <max>180</max>\n" 585 + " </value>\n" 586 + " </sensor>\n" 587 + " </conditions>\n" 588 + " </device-state>\n" 589 + "</device-state-config>\n"; 590 DeviceStateProviderImpl.ReadableConfig config = new TestReadableConfig(configString); 591 DeviceStateProviderImpl provider = DeviceStateProviderImpl.createFromConfig(mContext, 592 config); 593 594 DeviceStateProvider.Listener listener = mock(DeviceStateProvider.Listener.class); 595 provider.setListener(listener); 596 597 verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(), 598 eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED)); 599 assertArrayEquals( 600 new DeviceState[]{ 601 new DeviceState(1, "CLOSED", 0 /* flags */), 602 new DeviceState(2, "HALF_OPENED", 0 /* flags */) 603 }, mDeviceStateArrayCaptor.getValue()); 604 // onStateChanged() should not be called because the provider could not find the sensor. 605 verify(listener, never()).onStateChanged(mIntegerCaptor.capture()); 606 } 607 newSensor(String name, String type)608 private static Sensor newSensor(String name, String type) throws Exception { 609 Constructor<Sensor> constructor = Sensor.class.getDeclaredConstructor(); 610 constructor.setAccessible(true); 611 612 Sensor sensor = constructor.newInstance(); 613 FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mName"), name); 614 FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mStringType"), type); 615 return sensor; 616 } 617 618 private static final class TestReadableConfig implements 619 DeviceStateProviderImpl.ReadableConfig { 620 private final byte[] mData; 621 TestReadableConfig(String configFileData)622 TestReadableConfig(String configFileData) { 623 mData = configFileData.getBytes(); 624 } 625 626 @NonNull 627 @Override openRead()628 public InputStream openRead() throws IOException { 629 return new ByteArrayInputStream(mData); 630 } 631 } 632 } 633