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 com.example.android.vdmdemo.host;
18 
19 import android.companion.virtual.sensor.VirtualSensor;
20 import android.companion.virtual.sensor.VirtualSensorCallback;
21 import android.companion.virtual.sensor.VirtualSensorEvent;
22 import android.os.SystemClock;
23 import android.util.SparseArray;
24 
25 import androidx.annotation.NonNull;
26 
27 import com.example.android.vdmdemo.common.RemoteEventProto.RemoteEvent;
28 import com.example.android.vdmdemo.common.RemoteEventProto.RemoteSensorEvent;
29 import com.example.android.vdmdemo.common.RemoteEventProto.SensorConfiguration;
30 import com.example.android.vdmdemo.common.RemoteIo;
31 import com.google.common.primitives.Floats;
32 
33 import java.time.Duration;
34 import java.util.List;
35 import java.util.concurrent.TimeUnit;
36 import java.util.function.Consumer;
37 
38 final class RemoteSensorManager implements AutoCloseable {
39 
40     private final RemoteIo mRemoteIo;
41     private final SparseArray<VirtualSensor> mVirtualSensors = new SparseArray<>(); // Keyed by type
42     private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
43 
44     private final VirtualSensorCallback mVirtualSensorCallback = new SensorCallback();
45 
46     private class SensorCallback implements VirtualSensorCallback {
47         @Override
onConfigurationChanged( VirtualSensor sensor, boolean enabled, @NonNull Duration samplingPeriod, @NonNull Duration batchReportLatency)48         public void onConfigurationChanged(
49                 VirtualSensor sensor,
50                 boolean enabled,
51                 @NonNull Duration samplingPeriod,
52                 @NonNull Duration batchReportLatency) {
53             mRemoteIo.sendMessage(RemoteEvent.newBuilder()
54                     .setSensorConfiguration(SensorConfiguration.newBuilder()
55                             .setSensorType(sensor.getType())
56                             .setEnabled(enabled)
57                             .setSamplingPeriodUs(
58                                     (int) TimeUnit.MICROSECONDS.convert(samplingPeriod))
59                             .setBatchReportingLatencyUs(
60                                     (int) TimeUnit.MICROSECONDS.convert(batchReportLatency)))
61                     .build());
62         }
63     }
64 
RemoteSensorManager(RemoteIo remoteIo)65     RemoteSensorManager(RemoteIo remoteIo) {
66         this.mRemoteIo = remoteIo;
67         remoteIo.addMessageConsumer(mRemoteEventConsumer);
68     }
69 
70     @Override
close()71     public void close() {
72         mVirtualSensors.clear();
73         mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
74     }
75 
getVirtualSensorCallback()76     VirtualSensorCallback getVirtualSensorCallback() {
77         return mVirtualSensorCallback;
78     }
79 
setVirtualSensors(List<VirtualSensor> virtualSensorList)80     void setVirtualSensors(List<VirtualSensor> virtualSensorList) {
81         for (VirtualSensor virtualSensor : virtualSensorList) {
82             mVirtualSensors.put(virtualSensor.getType(), virtualSensor);
83         }
84     }
85 
processRemoteEvent(RemoteEvent remoteEvent)86     void processRemoteEvent(RemoteEvent remoteEvent) {
87         if (remoteEvent.hasSensorEvent()) {
88             RemoteSensorEvent sensorEvent = remoteEvent.getSensorEvent();
89             VirtualSensor sensor = mVirtualSensors.get(sensorEvent.getSensorType());
90             if (sensor != null) {
91                 sensor.sendEvent(
92                         new VirtualSensorEvent.Builder(Floats.toArray(sensorEvent.getValuesList()))
93                                 .setTimestampNanos(SystemClock.elapsedRealtimeNanos())
94                                 .build());
95             }
96         }
97     }
98 }
99