1 /* 2 * Copyright (C) 2023 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.virtualdevice.cts.sensor; 18 19 import static android.hardware.Sensor.TYPE_ACCELEROMETER; 20 import static android.hardware.SensorDirectChannel.RATE_NORMAL; 21 import static android.hardware.SensorDirectChannel.RATE_STOP; 22 import static android.hardware.SensorDirectChannel.TYPE_HARDWARE_BUFFER; 23 import static android.hardware.SensorDirectChannel.TYPE_MEMORY_FILE; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.junit.Assert.assertThrows; 28 import static org.junit.Assert.fail; 29 import static org.junit.Assume.assumeTrue; 30 import static org.mockito.ArgumentMatchers.any; 31 import static org.mockito.ArgumentMatchers.anyInt; 32 import static org.mockito.ArgumentMatchers.eq; 33 import static org.mockito.Mockito.doAnswer; 34 import static org.mockito.Mockito.never; 35 import static org.mockito.Mockito.timeout; 36 import static org.mockito.Mockito.verify; 37 import static org.mockito.Mockito.verifyNoMoreInteractions; 38 39 import static java.util.concurrent.TimeUnit.MICROSECONDS; 40 41 import android.companion.virtual.VirtualDeviceManager; 42 import android.companion.virtual.VirtualDeviceParams; 43 import android.companion.virtual.sensor.VirtualSensor; 44 import android.companion.virtual.sensor.VirtualSensorCallback; 45 import android.companion.virtual.sensor.VirtualSensorConfig; 46 import android.companion.virtual.sensor.VirtualSensorDirectChannelCallback; 47 import android.companion.virtual.sensor.VirtualSensorDirectChannelWriter; 48 import android.companion.virtual.sensor.VirtualSensorEvent; 49 import android.companion.virtualdevice.flags.Flags; 50 import android.content.Context; 51 import android.hardware.HardwareBuffer; 52 import android.hardware.Sensor; 53 import android.hardware.SensorDirectChannel; 54 import android.hardware.SensorEvent; 55 import android.hardware.SensorEventListener; 56 import android.hardware.SensorManager; 57 import android.os.MemoryFile; 58 import android.os.SharedMemory; 59 import android.platform.test.annotations.AppModeFull; 60 import android.platform.test.annotations.RequiresFlagsEnabled; 61 import android.system.ErrnoException; 62 import android.virtualdevice.cts.common.VirtualDeviceRule; 63 64 import androidx.annotation.Nullable; 65 import androidx.test.ext.junit.runners.AndroidJUnit4; 66 import androidx.test.platform.app.InstrumentationRegistry; 67 68 import org.junit.After; 69 import org.junit.Before; 70 import org.junit.Rule; 71 import org.junit.Test; 72 import org.junit.runner.RunWith; 73 import org.mockito.ArgumentCaptor; 74 import org.mockito.Mock; 75 import org.mockito.MockitoAnnotations; 76 import org.mockito.stubbing.Answer; 77 78 import java.io.UncheckedIOException; 79 import java.nio.ByteBuffer; 80 import java.nio.ByteOrder; 81 import java.time.Duration; 82 import java.util.Arrays; 83 import java.util.List; 84 import java.util.Random; 85 import java.util.concurrent.BlockingQueue; 86 import java.util.concurrent.LinkedBlockingQueue; 87 import java.util.concurrent.TimeUnit; 88 89 90 @RunWith(AndroidJUnit4.class) 91 @AppModeFull(reason = "VirtualDeviceManager cannot be accessed by instant apps") 92 public class VirtualSensorTest { 93 94 private static final String VIRTUAL_SENSOR_NAME = "VirtualAccelerometer"; 95 private static final String SECOND_SENSOR_NAME = VIRTUAL_SENSOR_NAME + "2"; 96 private static final String VIRTUAL_SENSOR_VENDOR = "VirtualDeviceVendor"; 97 98 private static final int CUSTOM_SENSOR_TYPE = Sensor.TYPE_DEVICE_PRIVATE_BASE + 9999; 99 100 private static final int SENSOR_TIMEOUT_MILLIS = 1000; 101 102 private static final int SENSOR_EVENT_SIZE = 104; 103 private static final int SENSOR_EVENT_COUNT = 100; 104 private static final int SHARED_MEMORY_SIZE = SENSOR_EVENT_COUNT * SENSOR_EVENT_SIZE; 105 106 @Rule 107 public VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault(); 108 @Nullable 109 private VirtualDeviceManager.VirtualDevice mVirtualDevice; 110 111 private SensorManager mSensorManager; 112 @Mock 113 private SensorManager.DynamicSensorCallback mDynamicSensorCallback; 114 115 private SensorManager mVirtualDeviceSensorManager; 116 private VirtualSensor mVirtualSensor; 117 private MemoryFile mMemoryFile; 118 private SensorDirectChannel mDirectChannel; 119 private VirtualSensorDirectChannelWriter mVirtualSensorDirectChannelWriter; 120 @Mock 121 private VirtualSensorCallback mVirtualSensorCallback; 122 @Mock 123 private VirtualSensorDirectChannelCallback mVirtualSensorDirectChannelCallback; 124 private final VirtualSensorEventListener mSensorEventListener = 125 new VirtualSensorEventListener(); 126 127 private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); 128 129 // Synchronize the IO to reduce test flakiness. 130 private final Object mDirectChannelIoLock = new Object(); 131 132 @Before setUp()133 public void setUp() { 134 MockitoAnnotations.initMocks(this); 135 mSensorManager = mContext.getSystemService(SensorManager.class); 136 assumeTrue(mSensorManager.getSensorList(Sensor.TYPE_ALL).size() > 0); 137 } 138 setUpVirtualSensor(VirtualSensorConfig sensorConfig)139 private VirtualSensor setUpVirtualSensor(VirtualSensorConfig sensorConfig) { 140 VirtualDeviceParams.Builder builder = new VirtualDeviceParams.Builder() 141 .setDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS, 142 VirtualDeviceParams.DEVICE_POLICY_CUSTOM); 143 if (sensorConfig != null) { 144 builder = builder 145 .addVirtualSensorConfig(sensorConfig) 146 .setVirtualSensorCallback( 147 mContext.getMainExecutor(), mVirtualSensorCallback); 148 if (sensorConfig.getDirectChannelTypesSupported() > 0) { 149 builder = builder.setVirtualSensorDirectChannelCallback( 150 mContext.getMainExecutor(), mVirtualSensorDirectChannelCallback); 151 } 152 } 153 mVirtualDevice = mVirtualDeviceRule.createManagedVirtualDevice(builder.build()); 154 Context deviceContext = mContext.createDeviceContext(mVirtualDevice.getDeviceId()); 155 mVirtualDeviceSensorManager = deviceContext.getSystemService(SensorManager.class); 156 if (sensorConfig == null) { 157 return null; 158 } else { 159 return mVirtualDevice.getVirtualSensorList().get(0); 160 } 161 } 162 setUpDirectChannel()163 private void setUpDirectChannel() throws Exception { 164 mVirtualSensor = setUpVirtualSensor( 165 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME) 166 .setDirectChannelTypesSupported(TYPE_MEMORY_FILE) 167 .setHighestDirectReportRateLevel(RATE_NORMAL) 168 .build()); 169 170 mMemoryFile = new MemoryFile("Sensor Channel", SHARED_MEMORY_SIZE); 171 mDirectChannel = mVirtualDeviceSensorManager.createDirectChannel(mMemoryFile); 172 } 173 174 @After tearDown()175 public void tearDown() { 176 if (mMemoryFile != null) { 177 mMemoryFile.close(); 178 } 179 if (mDirectChannel != null) { 180 mDirectChannel.close(); 181 } 182 } 183 184 @Test buildVirtualSensorConfig_hardwareBufferDirectChannel_throwsException()185 public void buildVirtualSensorConfig_hardwareBufferDirectChannel_throwsException() { 186 assertThrows( 187 IllegalArgumentException.class, 188 () -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME) 189 .setDirectChannelTypesSupported(TYPE_HARDWARE_BUFFER | TYPE_MEMORY_FILE) 190 .build()); 191 } 192 193 @Test getSensorList_noVirtualSensors_returnsEmptyList()194 public void getSensorList_noVirtualSensors_returnsEmptyList() { 195 mVirtualSensor = setUpVirtualSensor(/* sensorConfig= */ null); 196 assertThat(mVirtualSensor).isNull(); 197 assertThat(mVirtualDeviceSensorManager.getSensorList(TYPE_ACCELEROMETER)).isEmpty(); 198 } 199 200 @Test getSensorList_returnsVirtualSensor()201 public void getSensorList_returnsVirtualSensor() { 202 mVirtualSensor = setUpVirtualSensor( 203 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME) 204 .setVendor(VIRTUAL_SENSOR_VENDOR) 205 .setDirectChannelTypesSupported(TYPE_MEMORY_FILE) 206 .setHighestDirectReportRateLevel(RATE_NORMAL) 207 .setMaximumRange(1.2f) 208 .setResolution(3.4f) 209 .setPower(5.6f) 210 .setMinDelay(7) 211 .setMaxDelay(8) 212 .build()); 213 214 assertThat(mVirtualSensor.getType()).isEqualTo(TYPE_ACCELEROMETER); 215 assertThat(mVirtualSensor.getName()).isEqualTo(VIRTUAL_SENSOR_NAME); 216 assertThat(mVirtualSensor.getDeviceId()).isEqualTo(mVirtualDevice.getDeviceId()); 217 218 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 219 List<Sensor> sensors = mVirtualDeviceSensorManager.getSensorList(TYPE_ACCELEROMETER); 220 Sensor defaultDeviceSensor = mSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 221 222 assertThat(sensors).containsExactly(sensor); 223 assertThat(sensor).isNotEqualTo(defaultDeviceSensor); 224 225 assertThat(sensor.getName()).isEqualTo(VIRTUAL_SENSOR_NAME); 226 assertThat(sensor.getVendor()).isEqualTo(VIRTUAL_SENSOR_VENDOR); 227 assertThat(sensor.getType()).isEqualTo(TYPE_ACCELEROMETER); 228 assertThat(sensor.isDynamicSensor()).isFalse(); 229 assertThat(sensor.isDirectChannelTypeSupported(TYPE_MEMORY_FILE)).isTrue(); 230 assertThat(sensor.isDirectChannelTypeSupported(TYPE_HARDWARE_BUFFER)).isFalse(); 231 assertThat(sensor.getHighestDirectReportRateLevel()).isEqualTo(RATE_NORMAL); 232 assertThat(sensor.getMaximumRange()).isEqualTo(1.2f); 233 assertThat(sensor.getResolution()).isEqualTo(3.4f); 234 assertThat(sensor.getPower()).isEqualTo(5.6f); 235 assertThat(sensor.getMinDelay()).isEqualTo(7); 236 assertThat(sensor.getMaxDelay()).isEqualTo(8); 237 assertThat(sensor.getStringType()).isEqualTo(Sensor.STRING_TYPE_ACCELEROMETER); 238 assertThat(sensor.getReportingMode()).isEqualTo(Sensor.REPORTING_MODE_CONTINUOUS); 239 assertThat(sensor.isWakeUpSensor()).isFalse(); 240 } 241 242 @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER) 243 @Test getDefaultSensor_wakeUpSensor()244 public void getDefaultSensor_wakeUpSensor() { 245 mVirtualSensor = setUpVirtualSensor( 246 new VirtualSensorConfig.Builder(Sensor.TYPE_PROXIMITY, VIRTUAL_SENSOR_NAME) 247 .setWakeUpSensor(true) 248 .setReportingMode(Sensor.REPORTING_MODE_ON_CHANGE) 249 .build()); 250 251 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); 252 assertThat(sensor.getName()).isEqualTo(VIRTUAL_SENSOR_NAME); 253 assertThat(sensor.getReportingMode()).isEqualTo(Sensor.REPORTING_MODE_ON_CHANGE); 254 assertThat(sensor.isWakeUpSensor()).isTrue(); 255 } 256 257 @Test getSensorList_isCached()258 public void getSensorList_isCached() { 259 mVirtualSensor = setUpVirtualSensor( 260 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 261 262 final List<Sensor> allSensors = mVirtualDeviceSensorManager.getSensorList(Sensor.TYPE_ALL); 263 assertThat(allSensors).isSameInstanceAs( 264 mVirtualDeviceSensorManager.getSensorList(Sensor.TYPE_ALL)); 265 266 final List<Sensor> sensors = mVirtualDeviceSensorManager.getSensorList(TYPE_ACCELEROMETER); 267 assertThat(sensors).isSameInstanceAs( 268 mVirtualDeviceSensorManager.getSensorList(TYPE_ACCELEROMETER)); 269 } 270 271 @Test createVirtualSensor_multipleSensorsSameType()272 public void createVirtualSensor_multipleSensorsSameType() { 273 VirtualDeviceParams.Builder builder = new VirtualDeviceParams.Builder() 274 .setDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS, 275 VirtualDeviceParams.DEVICE_POLICY_CUSTOM) 276 .addVirtualSensorConfig( 277 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME) 278 .build()) 279 .addVirtualSensorConfig( 280 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SECOND_SENSOR_NAME) 281 .build()) 282 .setVirtualSensorCallback( 283 mContext.getMainExecutor(), mVirtualSensorCallback); 284 mVirtualDevice = mVirtualDeviceRule.createManagedVirtualDevice(builder.build()); 285 Context deviceContext = mContext.createDeviceContext(mVirtualDevice.getDeviceId()); 286 mVirtualDeviceSensorManager = deviceContext.getSystemService(SensorManager.class); 287 288 List<VirtualSensor> virtualSensors = mVirtualDevice.getVirtualSensorList(); 289 assertThat(virtualSensors).hasSize(2); 290 assertThat(virtualSensors.get(0).getType()).isEqualTo(TYPE_ACCELEROMETER); 291 assertThat(virtualSensors.get(0).getName()).isEqualTo(VIRTUAL_SENSOR_NAME); 292 assertThat(virtualSensors.get(0).getDeviceId()).isEqualTo(mVirtualDevice.getDeviceId()); 293 assertThat(virtualSensors.get(1).getType()).isEqualTo(TYPE_ACCELEROMETER); 294 assertThat(virtualSensors.get(1).getName()).isEqualTo(SECOND_SENSOR_NAME); 295 assertThat(virtualSensors.get(1).getDeviceId()).isEqualTo(mVirtualDevice.getDeviceId()); 296 297 List<Sensor> sensors = mVirtualDeviceSensorManager.getSensorList(TYPE_ACCELEROMETER); 298 assertThat(sensors).hasSize(2); 299 assertThat(sensors.get(0).getName()).isEqualTo(VIRTUAL_SENSOR_NAME); 300 assertThat(sensors.get(0).getType()).isEqualTo(TYPE_ACCELEROMETER); 301 assertThat(sensors.get(1).getName()).isEqualTo(SECOND_SENSOR_NAME); 302 assertThat(sensors.get(1).getType()).isEqualTo(TYPE_ACCELEROMETER); 303 } 304 305 @Test createVirtualSensor_dynamicSensorCallback_notCalled()306 public void createVirtualSensor_dynamicSensorCallback_notCalled() { 307 mSensorManager.registerDynamicSensorCallback(mDynamicSensorCallback); 308 309 mVirtualSensor = setUpVirtualSensor( 310 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 311 312 verify(mDynamicSensorCallback, never()).onDynamicSensorConnected(any()); 313 314 mSensorManager.unregisterDynamicSensorCallback(mDynamicSensorCallback); 315 } 316 317 @Test closeVirtualDevice_removesSensor()318 public void closeVirtualDevice_removesSensor() { 319 mVirtualSensor = setUpVirtualSensor( 320 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 321 mVirtualDevice.close(); 322 323 // The virtual device ID is no longer valid, SensorManager falls back to default device. 324 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 325 Sensor defaultDeviceSensor = mSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 326 327 if (defaultDeviceSensor == null) { 328 assertThat(sensor).isNull(); 329 } else { 330 assertThat(sensor.getHandle()).isEqualTo(defaultDeviceSensor.getHandle()); 331 assertThat(sensor.getName()).isEqualTo(defaultDeviceSensor.getName()); 332 } 333 } 334 335 @Test registerListener_triggersVirtualSensorCallback()336 public void registerListener_triggersVirtualSensorCallback() { 337 mVirtualSensor = setUpVirtualSensor( 338 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 339 340 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 341 342 final int samplingPeriodMicros = 2345000; 343 final int maxReportLatencyMicros = 678000; 344 mVirtualDeviceSensorManager.registerListener( 345 mSensorEventListener, sensor, samplingPeriodMicros, maxReportLatencyMicros); 346 347 final Duration expectedSamplingPeriod = 348 Duration.ofNanos(MICROSECONDS.toNanos(samplingPeriodMicros)); 349 final Duration expectedReportLatency = 350 Duration.ofNanos(MICROSECONDS.toNanos(maxReportLatencyMicros)); 351 352 ArgumentCaptor<VirtualSensor> virtualSensor = ArgumentCaptor.forClass(VirtualSensor.class); 353 verify(mVirtualSensorCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 354 .onConfigurationChanged(virtualSensor.capture(), eq(true), 355 eq(expectedSamplingPeriod), eq(expectedReportLatency)); 356 assertThat(virtualSensor.getValue().getHandle()).isEqualTo(mVirtualSensor.getHandle()); 357 358 mVirtualDeviceSensorManager.unregisterListener(mSensorEventListener); 359 360 verify(mVirtualSensorCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 361 .onConfigurationChanged(virtualSensor.capture(), eq(false), any(Duration.class), 362 any(Duration.class)); 363 assertThat(virtualSensor.getValue().getHandle()).isEqualTo(mVirtualSensor.getHandle()); 364 365 verifyNoMoreInteractions(mVirtualSensorCallback); 366 } 367 368 @Test sendEvent_reachesRegisteredListeners()369 public void sendEvent_reachesRegisteredListeners() { 370 mVirtualSensor = setUpVirtualSensor( 371 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 372 373 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 374 375 mVirtualDeviceSensorManager.registerListener( 376 mSensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); 377 378 final VirtualSensorEvent firstEvent = 379 new VirtualSensorEvent.Builder(new float[] {0.1f, 2.3f, 4.5f}).build(); 380 mVirtualSensor.sendEvent(firstEvent); 381 382 mSensorEventListener.assertReceivedSensorEvent(sensor, firstEvent); 383 384 final VirtualSensorEvent secondEvent = 385 new VirtualSensorEvent.Builder(new float[] {6.7f, 8.9f, 0.1f}).build(); 386 mVirtualSensor.sendEvent(secondEvent); 387 388 mSensorEventListener.assertReceivedSensorEvent(sensor, secondEvent); 389 390 mVirtualDeviceSensorManager.unregisterListener(mSensorEventListener); 391 392 final VirtualSensorEvent thirdEvent = 393 new VirtualSensorEvent.Builder(new float[] {2.3f, 4.5f, 6.7f}).build(); 394 mVirtualSensor.sendEvent(thirdEvent); 395 396 mSensorEventListener.assertNoMoreEvents(); 397 } 398 399 @Test sendEvent_explicitTimestampSpecified()400 public void sendEvent_explicitTimestampSpecified() { 401 mVirtualSensor = setUpVirtualSensor( 402 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 403 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 404 mVirtualDeviceSensorManager.registerListener( 405 mSensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); 406 407 VirtualSensorEvent event = 408 new VirtualSensorEvent.Builder(new float[] {0.1f, 2.3f, 4.5f}) 409 .setTimestampNanos(System.nanoTime()) 410 .build(); 411 mVirtualSensor.sendEvent(event); 412 413 mSensorEventListener.assertReceivedSensorEvent(sensor, event); 414 415 mVirtualDeviceSensorManager.unregisterListener(mSensorEventListener); 416 417 mSensorEventListener.assertNoMoreEvents(); 418 } 419 420 @Test sendEvent_invalidValues_eventIsDropped()421 public void sendEvent_invalidValues_eventIsDropped() { 422 mVirtualSensor = setUpVirtualSensor( 423 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 424 425 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 426 427 mVirtualDeviceSensorManager.registerListener( 428 mSensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); 429 430 final VirtualSensorEvent firstEvent = 431 new VirtualSensorEvent.Builder(new float[] {0.1f}).build(); 432 mVirtualSensor.sendEvent(firstEvent); 433 434 final VirtualSensorEvent secondEvent = 435 new VirtualSensorEvent.Builder(new float[] {2.3f, 4.5f, 6.7f, 8.9f}).build(); 436 mVirtualSensor.sendEvent(secondEvent); 437 438 final VirtualSensorEvent thirdEvent = 439 new VirtualSensorEvent.Builder(new float[] {7.7f, 8.8f}).build(); 440 mVirtualSensor.sendEvent(thirdEvent); 441 442 mSensorEventListener.assertNoMoreEvents(); 443 444 mVirtualDeviceSensorManager.unregisterListener(mSensorEventListener); 445 } 446 447 @Test virtualSensor_arbitrarySensorType()448 public void virtualSensor_arbitrarySensorType() { 449 mVirtualSensor = setUpVirtualSensor( 450 new VirtualSensorConfig.Builder(CUSTOM_SENSOR_TYPE, VIRTUAL_SENSOR_NAME).build()); 451 452 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(CUSTOM_SENSOR_TYPE); 453 454 mVirtualDeviceSensorManager.registerListener( 455 mSensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL); 456 457 float[] values = new float[16]; 458 Arrays.fill(values, 1.2f); 459 460 final VirtualSensorEvent validEvent = new VirtualSensorEvent.Builder(values).build(); 461 mVirtualSensor.sendEvent(validEvent); 462 463 mSensorEventListener.assertReceivedSensorEvent(sensor, validEvent); 464 465 // Sensor events can have at most 16 values. Check that events with more values are dropped. 466 float[] invalidValues = new float[17]; 467 Arrays.fill(values, 3.4f); 468 final VirtualSensorEvent invalidEvent = 469 new VirtualSensorEvent.Builder(invalidValues).build(); 470 mVirtualSensor.sendEvent(invalidEvent); 471 472 mSensorEventListener.assertNoMoreEvents(); 473 474 mVirtualDeviceSensorManager.unregisterListener(mSensorEventListener); 475 } 476 477 @Test directConnection_memoryFile_notSupported()478 public void directConnection_memoryFile_notSupported() throws Exception { 479 mVirtualSensor = setUpVirtualSensor( 480 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 481 482 MemoryFile memoryFile = new MemoryFile("Sensor Channel", SHARED_MEMORY_SIZE); 483 SensorDirectChannel channel = mVirtualDeviceSensorManager.createDirectChannel(memoryFile); 484 485 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 486 assertThat(channel.configure(sensor, RATE_NORMAL)).isEqualTo(0); 487 } 488 489 @Test directConnection_hardwareBuffer_throwsException()490 public void directConnection_hardwareBuffer_throwsException() { 491 // Skip this test if hardware buffer direct channel is generally not supported on the device 492 assumeTrue(mSensorManager.getSensorList(Sensor.TYPE_ALL).stream().anyMatch( 493 s -> s.isDirectChannelTypeSupported(TYPE_HARDWARE_BUFFER))); 494 495 mVirtualSensor = setUpVirtualSensor( 496 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME).build()); 497 498 try (HardwareBuffer hardwareBuffer = createSensorsHardwareBuffer()) { 499 assertThrows(UncheckedIOException.class, 500 () -> mVirtualDeviceSensorManager.createDirectChannel(hardwareBuffer)); 501 } 502 } 503 504 @Test directConnection_memoryFile_onlyValidForVirtualDevice()505 public void directConnection_memoryFile_onlyValidForVirtualDevice() throws Exception { 506 setUpDirectChannel(); 507 508 // The channel is created for the virtual device ID, configuring it for a sensor of the 509 // default device should not be allowed. 510 Sensor defaultDeviceSensor = 511 mSensorManager.getSensorList(Sensor.TYPE_ALL).stream().findFirst().orElse(null); 512 assumeTrue(defaultDeviceSensor != null); 513 assertThat(mDirectChannel.configure(defaultDeviceSensor, RATE_NORMAL)).isEqualTo(0); 514 } 515 516 @Test directConnectionForDefaultDevice_memoryFile_notValidForVirtualDevice()517 public void directConnectionForDefaultDevice_memoryFile_notValidForVirtualDevice() 518 throws Exception { 519 // Skip this test if memory file direct channel is generally not supported on the device. 520 assumeTrue(mSensorManager.getSensorList(Sensor.TYPE_ALL).stream().anyMatch( 521 s -> s.isDirectChannelTypeSupported(TYPE_MEMORY_FILE))); 522 523 MemoryFile memoryFile = new MemoryFile("Sensor Channel", SHARED_MEMORY_SIZE); 524 SensorDirectChannel channel = mSensorManager.createDirectChannel(memoryFile); 525 526 mVirtualSensor = setUpVirtualSensor( 527 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME) 528 .setDirectChannelTypesSupported(TYPE_MEMORY_FILE) 529 .setHighestDirectReportRateLevel(RATE_NORMAL) 530 .build()); 531 532 // The channel is created for the default device ID, configuring it for a sensor of the 533 // virtual device should not be allowed. 534 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 535 assertThat(channel.configure(sensor, RATE_NORMAL)).isEqualTo(0); 536 } 537 538 @Test directConnection_memoryFile_notValidForAnotherVirtualDevice()539 public void directConnection_memoryFile_notValidForAnotherVirtualDevice() throws Exception { 540 setUpDirectChannel(); 541 542 // Creates a new virtual device, while the direct channel is associated with the Sensor 543 // manager of the first virtual device. 544 mVirtualSensor = setUpVirtualSensor( 545 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME) 546 .setDirectChannelTypesSupported(TYPE_MEMORY_FILE) 547 .setHighestDirectReportRateLevel(RATE_NORMAL) 548 .build()); 549 550 // The channel is configured for the first device and the sensor does not belong to it. 551 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 552 assertThat(mDirectChannel.configure(sensor, RATE_NORMAL)).isEqualTo(0); 553 } 554 555 @Test directConnectionForDefaultDevice_hardwareBuffer_notValidForVirtualDevice()556 public void directConnectionForDefaultDevice_hardwareBuffer_notValidForVirtualDevice() { 557 // Skip this test if hardware buffer direct channel is generally not supported on the device 558 assumeTrue(mSensorManager.getSensorList(Sensor.TYPE_ALL).stream().anyMatch( 559 s -> s.isDirectChannelTypeSupported(TYPE_HARDWARE_BUFFER))); 560 561 try (HardwareBuffer hardwareBuffer = createSensorsHardwareBuffer()) { 562 SensorDirectChannel channel = mSensorManager.createDirectChannel(hardwareBuffer); 563 564 mVirtualSensor = setUpVirtualSensor( 565 new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, 566 VIRTUAL_SENSOR_NAME).build()); 567 568 // The channel is created for the default device ID, configuring it for a sensor of the 569 // virtual device should not be allowed. 570 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 571 assertThat(channel.configure(sensor, RATE_NORMAL)).isEqualTo(0); 572 } 573 } 574 575 @Test directConnection_memoryFile_triggersVirtualSensorCallback()576 public void directConnection_memoryFile_triggersVirtualSensorCallback() throws Exception { 577 setUpDirectChannel(); 578 579 ArgumentCaptor<Integer> channelHandle = ArgumentCaptor.forClass(Integer.class); 580 ArgumentCaptor<SharedMemory> sharedMemory = ArgumentCaptor.forClass(SharedMemory.class); 581 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 582 .onDirectChannelCreated(channelHandle.capture(), sharedMemory.capture()); 583 584 doAnswer((Answer<Void>) i -> { 585 sharedMemory.getValue().close(); 586 return null; 587 }).when(mVirtualSensorDirectChannelCallback) 588 .onDirectChannelDestroyed(channelHandle.getValue()); 589 590 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 591 int reportToken = mDirectChannel.configure(sensor, RATE_NORMAL); 592 assertThat(reportToken).isGreaterThan(0); 593 594 ArgumentCaptor<VirtualSensor> virtualSensor = ArgumentCaptor.forClass(VirtualSensor.class); 595 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 596 .onDirectChannelConfigured(eq(channelHandle.getValue()), virtualSensor.capture(), 597 eq(RATE_NORMAL), eq(reportToken)); 598 assertThat(virtualSensor.getValue().getHandle()).isEqualTo(mVirtualSensor.getHandle()); 599 600 assertThat(mDirectChannel.configure(sensor, RATE_STOP)).isEqualTo(1); 601 602 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 603 .onDirectChannelConfigured(eq(channelHandle.getValue()), virtualSensor.capture(), 604 eq(RATE_STOP), eq(reportToken)); 605 assertThat(virtualSensor.getValue().getHandle()).isEqualTo(mVirtualSensor.getHandle()); 606 607 mDirectChannel.close(); 608 mDirectChannel = null; 609 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 610 .onDirectChannelDestroyed(eq(channelHandle.getValue())); 611 } 612 613 @Test directConnection_memoryFile_stopAll_triggersVirtualSensorCallback()614 public void directConnection_memoryFile_stopAll_triggersVirtualSensorCallback() 615 throws Exception { 616 setUpDirectChannel(); 617 618 ArgumentCaptor<Integer> channelHandle = ArgumentCaptor.forClass(Integer.class); 619 ArgumentCaptor<SharedMemory> sharedMemory = ArgumentCaptor.forClass(SharedMemory.class); 620 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 621 .onDirectChannelCreated(channelHandle.capture(), sharedMemory.capture()); 622 623 doAnswer((Answer<Void>) i -> { 624 sharedMemory.getValue().close(); 625 return null; 626 }).when(mVirtualSensorDirectChannelCallback) 627 .onDirectChannelDestroyed(channelHandle.getValue()); 628 629 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 630 int reportToken = mDirectChannel.configure(sensor, RATE_NORMAL); 631 assertThat(reportToken).isGreaterThan(0); 632 633 ArgumentCaptor<VirtualSensor> virtualSensor = ArgumentCaptor.forClass(VirtualSensor.class); 634 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 635 .onDirectChannelConfigured(eq(channelHandle.getValue()), virtualSensor.capture(), 636 eq(RATE_NORMAL), eq(reportToken)); 637 assertThat(virtualSensor.getValue().getHandle()).isEqualTo(mVirtualSensor.getHandle()); 638 639 assertThat(mDirectChannel.configure(/*sensor=*/null, RATE_STOP)).isEqualTo(1); 640 641 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 642 .onDirectChannelConfigured(eq(channelHandle.getValue()), virtualSensor.capture(), 643 eq(RATE_STOP), eq(reportToken)); 644 assertThat(virtualSensor.getValue().getHandle()).isEqualTo(mVirtualSensor.getHandle()); 645 } 646 647 @Test directConnection_memoryFile_injectEvents()648 public void directConnection_memoryFile_injectEvents() throws Exception { 649 setUpDirectChannel(); 650 651 ArgumentCaptor<Integer> channelHandle = ArgumentCaptor.forClass(Integer.class); 652 ArgumentCaptor<SharedMemory> sharedMemory = ArgumentCaptor.forClass(SharedMemory.class); 653 verify(mVirtualSensorDirectChannelCallback, timeout(SENSOR_TIMEOUT_MILLIS).times(1)) 654 .onDirectChannelCreated(channelHandle.capture(), sharedMemory.capture()); 655 656 doAnswer((Answer<Void>) i -> { 657 int reportToken = (int) i.getArguments()[3]; 658 writeDirectChannelEvents(reportToken, sharedMemory.getValue()); 659 return null; 660 }).when(mVirtualSensorDirectChannelCallback) 661 .onDirectChannelConfigured( 662 eq(channelHandle.getValue()), any(), eq(RATE_NORMAL), anyInt()); 663 664 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 665 int reportToken = mDirectChannel.configure(sensor, RATE_NORMAL); 666 verifyDirectChannelEvents(reportToken); 667 668 doAnswer((Answer<Void>) i -> { 669 sharedMemory.getValue().close(); 670 return null; 671 }).when(mVirtualSensorDirectChannelCallback) 672 .onDirectChannelDestroyed(channelHandle.getValue()); 673 } 674 675 @Test directConnection_memoryFile_injectEvents_withHelperWriter()676 public void directConnection_memoryFile_injectEvents_withHelperWriter() throws Exception { 677 mVirtualSensorDirectChannelWriter = new VirtualSensorDirectChannelWriter(); 678 679 doAnswer((Answer<Void>) i -> { 680 int channelHandle = (int) i.getArguments()[0]; 681 SharedMemory sharedMemory = (SharedMemory) i.getArguments()[1]; 682 mVirtualSensorDirectChannelWriter.addChannel(channelHandle, sharedMemory); 683 return null; 684 }).when(mVirtualSensorDirectChannelCallback).onDirectChannelCreated(anyInt(), any()); 685 686 doAnswer((Answer<Void>) i -> { 687 int channelHandle = (int) i.getArguments()[0]; 688 mVirtualSensorDirectChannelWriter.removeChannel(channelHandle); 689 return null; 690 }).when(mVirtualSensorDirectChannelCallback).onDirectChannelDestroyed(anyInt()); 691 692 doAnswer((Answer<Void>) i -> { 693 int channelHandle = (int) i.getArguments()[0]; 694 VirtualSensor sensor = (VirtualSensor) i.getArguments()[1]; 695 int rateLevel = (int) i.getArguments()[2]; 696 int reportToken = (int) i.getArguments()[3]; 697 assertThat(mVirtualSensorDirectChannelWriter.configureChannel( 698 channelHandle, sensor, rateLevel, reportToken)).isTrue(); 699 Random random = new Random(); 700 701 for (int eventCount = 0; eventCount < SENSOR_EVENT_COUNT * 2; ++eventCount) { 702 float[] values = new float[] { 703 reportToken + eventCount * 0.01f, 704 reportToken + eventCount * 0.02f, 705 reportToken + eventCount * 0.03f, 706 }; 707 synchronized (mDirectChannelIoLock) { 708 assertThat(mVirtualSensorDirectChannelWriter.writeSensorEvent(sensor, 709 new VirtualSensorEvent.Builder(values) 710 .setTimestampNanos(System.nanoTime()) 711 .build())) 712 .isTrue(); 713 } 714 try { 715 Thread.sleep(random.nextInt(10)); // Sleep random time of 0-20ms. 716 } catch (InterruptedException e) { 717 fail("Interrupted while writing sensor events: " + e); 718 } 719 } 720 return null; 721 }).when(mVirtualSensorDirectChannelCallback) 722 .onDirectChannelConfigured(anyInt(), any(), eq(RATE_NORMAL), anyInt()); 723 724 setUpDirectChannel(); 725 726 Sensor sensor = mVirtualDeviceSensorManager.getDefaultSensor(TYPE_ACCELEROMETER); 727 int reportToken = mDirectChannel.configure(sensor, RATE_NORMAL); 728 verifyDirectChannelEvents(reportToken); 729 } 730 731 private static class VirtualSensorEventListener implements SensorEventListener { 732 private final BlockingQueue<SensorEvent> mEvents = new LinkedBlockingQueue<>(); 733 734 @Override onSensorChanged(SensorEvent event)735 public void onSensorChanged(SensorEvent event) { 736 try { 737 mEvents.put(event); 738 } catch (InterruptedException ex) { 739 fail("Interrupted while adding a SensorEvent to the queue"); 740 } 741 } 742 743 @Override onAccuracyChanged(Sensor sensor, int accuracy)744 public void onAccuracyChanged(Sensor sensor, int accuracy) { 745 } 746 assertReceivedSensorEvent(Sensor sensor, VirtualSensorEvent expected)747 public void assertReceivedSensorEvent(Sensor sensor, VirtualSensorEvent expected) { 748 SensorEvent event = waitForEvent(); 749 if (event == null) { 750 fail("Did not receive SensorEvent with values " 751 + Arrays.toString(expected.getValues())); 752 } 753 754 assertThat(event.sensor).isEqualTo(sensor); 755 assertThat(event.values).isEqualTo(expected.getValues()); 756 assertThat(event.timestamp).isEqualTo(expected.getTimestampNanos()); 757 } 758 assertNoMoreEvents()759 public void assertNoMoreEvents() { 760 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 761 SensorEvent event = waitForEvent(); 762 if (event != null) { 763 fail("Received extra SensorEvent with values: " + Arrays.toString(event.values)); 764 } 765 } 766 waitForEvent()767 private SensorEvent waitForEvent() { 768 try { 769 return mEvents.poll(5, TimeUnit.SECONDS); 770 } catch (InterruptedException e) { 771 fail("Interrupted while waiting for SensorEvent"); 772 return null; 773 } 774 } 775 } 776 writeDirectChannelEvents(int reportToken, SharedMemory sharedMemory)777 private void writeDirectChannelEvents(int reportToken, SharedMemory sharedMemory) { 778 int offset = 0; 779 int eventCount = 0; 780 ByteBuffer event = ByteBuffer.allocate(SENSOR_EVENT_SIZE); 781 event.order(ByteOrder.nativeOrder()); 782 Random random = new Random(); 783 ByteBuffer memoryMapping = null; 784 try { 785 memoryMapping = sharedMemory.mapReadWrite(); 786 } catch (ErrnoException e) { 787 sharedMemory.close(); 788 fail("Could not map the shared memory for IO: " + e); 789 } 790 791 while (eventCount < SENSOR_EVENT_COUNT * 2) { 792 event.position(0); 793 event.putInt(SENSOR_EVENT_SIZE); 794 event.putInt(reportToken); 795 event.putInt(TYPE_ACCELEROMETER); 796 event.putInt(++eventCount); 797 event.putLong(System.nanoTime()); 798 // sensor values 799 event.putFloat(reportToken + eventCount * 0.01f); 800 event.putFloat(reportToken + eventCount * 0.02f); 801 event.putFloat(reportToken + eventCount * 0.03f); 802 803 memoryMapping.position(offset); 804 synchronized (mDirectChannelIoLock) { 805 memoryMapping.put(event.array(), 0, SENSOR_EVENT_SIZE); 806 } 807 try { 808 Thread.sleep(random.nextInt(10)); // Sleep random time of 0-20ms. 809 } catch (InterruptedException e) { 810 sharedMemory.close(); 811 fail("Interrupted while writing sensor events: " + e); 812 } 813 814 offset += SENSOR_EVENT_SIZE; 815 if (offset + SENSOR_EVENT_SIZE >= sharedMemory.getSize()) { 816 offset = 0; 817 } 818 } 819 } 820 verifyDirectChannelEvents(int reportToken)821 private void verifyDirectChannelEvents(int reportToken) throws Exception { 822 int offset = 0; 823 int eventCount = 0; 824 ByteBuffer byteBuffer = ByteBuffer.allocate(SENSOR_EVENT_SIZE); 825 byteBuffer.order(ByteOrder.nativeOrder()); 826 827 while (eventCount < SENSOR_EVENT_COUNT * 2) { 828 synchronized (mDirectChannelIoLock) { 829 assertThat(mMemoryFile.readBytes(byteBuffer.array(), offset, 0, SENSOR_EVENT_SIZE)) 830 .isEqualTo(SENSOR_EVENT_SIZE); 831 } 832 byteBuffer.position(0); 833 int eventSize = byteBuffer.getInt(); 834 int actualReportToken = byteBuffer.getInt(); 835 if (reportToken != actualReportToken) { 836 Thread.sleep(10); 837 continue; 838 } 839 int sensorType = byteBuffer.getInt(); 840 int eventCounter = byteBuffer.getInt(); 841 842 if (eventCounter > 0) { 843 if (eventCounter != eventCount + 1) { 844 Thread.sleep(10); 845 continue; 846 } 847 eventCount++; 848 849 assertThat(eventSize).isEqualTo(SENSOR_EVENT_SIZE); 850 assertThat(sensorType).isEqualTo(TYPE_ACCELEROMETER); 851 852 byteBuffer.getLong(); // timestamp 853 854 // verify the sensor values 855 assertThat(byteBuffer.getFloat()) 856 .isEqualTo(reportToken + eventCounter * 0.1f); 857 assertThat(byteBuffer.getFloat()) 858 .isEqualTo(reportToken + eventCounter * 0.2f); 859 assertThat(byteBuffer.getFloat()) 860 .isEqualTo(reportToken + eventCounter * 0.3f); 861 862 offset += SENSOR_EVENT_SIZE; 863 if (offset + SENSOR_EVENT_SIZE >= SHARED_MEMORY_SIZE) { 864 offset = 0; 865 } 866 } 867 } 868 } 869 createSensorsHardwareBuffer()870 private static HardwareBuffer createSensorsHardwareBuffer() { 871 return HardwareBuffer.create( 872 /*width=*/SHARED_MEMORY_SIZE, /*height=*/1, HardwareBuffer.BLOB, /*layers=*/1, 873 HardwareBuffer.USAGE_CPU_READ_OFTEN 874 | HardwareBuffer.USAGE_GPU_DATA_BUFFER 875 | HardwareBuffer.USAGE_SENSOR_DIRECT_DATA); 876 } 877 } 878