• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.client;
18 
19 import android.content.Context;
20 import android.hardware.Sensor;
21 import android.hardware.SensorAdditionalInfo;
22 import android.hardware.SensorEvent;
23 import android.hardware.SensorEventCallback;
24 import android.hardware.SensorManager;
25 import android.os.Handler;
26 import android.os.HandlerThread;
27 
28 import com.example.android.vdmdemo.common.RemoteEventProto.RemoteEvent;
29 import com.example.android.vdmdemo.common.RemoteEventProto.RemoteSensorEvent;
30 import com.example.android.vdmdemo.common.RemoteEventProto.SensorCapabilities;
31 import com.example.android.vdmdemo.common.RemoteEventProto.SensorConfiguration;
32 import com.example.android.vdmdemo.common.RemoteIo;
33 import com.google.common.primitives.Floats;
34 
35 import dagger.hilt.android.qualifiers.ApplicationContext;
36 import dagger.hilt.android.scopes.ActivityScoped;
37 
38 import java.util.List;
39 import java.util.Objects;
40 import java.util.function.Consumer;
41 import java.util.stream.Collectors;
42 import java.util.stream.Stream;
43 
44 import javax.inject.Inject;
45 
46 @ActivityScoped
47 final class VirtualSensorController implements AutoCloseable {
48 
49     private final RemoteIo mRemoteIo;
50     private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
51     private final SensorManager mSensorManager;
52     private final HandlerThread mListenerThread;
53     private final Handler mHandler;
54 
55     private final SensorEventCallback mSensorEventCallback = new SensorEventCallback() {
56         @Override
57         public void onSensorChanged(SensorEvent event) {
58             mRemoteIo.sendMessage(RemoteEvent.newBuilder()
59                     .setSensorEvent(RemoteSensorEvent.newBuilder()
60                             .setSensorType(event.sensor.getType())
61                             .setAdditionalInfoType(-1)
62                             .addAllValues(Floats.asList(event.values)))
63                     .build());
64         }
65 
66         @Override
67         public void onSensorAdditionalInfo(SensorAdditionalInfo info) {
68             if (info.type != SensorAdditionalInfo.TYPE_INTERNAL_TEMPERATURE) {
69                 return;
70             }
71             mRemoteIo.sendMessage(RemoteEvent.newBuilder()
72                     .setSensorEvent(RemoteSensorEvent.newBuilder()
73                             .setSensorType(info.sensor.getType())
74                             .setAdditionalInfoType(info.type)
75                             .addAllValues(List.of(info.floatValues[0])))
76                     .build());
77         }
78     };
79 
80     @Inject
VirtualSensorController(@pplicationContext Context context, RemoteIo remoteIo)81     VirtualSensorController(@ApplicationContext Context context, RemoteIo remoteIo) {
82         mSensorManager = context.getSystemService(SensorManager.class);
83         mRemoteIo = remoteIo;
84 
85         mListenerThread = new HandlerThread("VirtualSensorListener");
86         mListenerThread.start();
87         mHandler = new Handler(mListenerThread.getLooper());
88 
89         remoteIo.addMessageConsumer(mRemoteEventConsumer);
90     }
91 
92     @Override
close()93     public void close() {
94         mSensorManager.unregisterListener(mSensorEventCallback);
95         mListenerThread.quitSafely();
96         mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
97     }
98 
getSensorCapabilities()99     public List<SensorCapabilities> getSensorCapabilities() {
100         // For demo purposes we only need a single accelerometer and proximity sensor.
101         return Stream.of(
102                         mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
103                         mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY))
104                 .filter(Objects::nonNull)
105                 .map(VirtualSensorController::createSensorCapabilitiesFromSensor)
106                 .collect(Collectors.toList());
107     }
108 
createSensorCapabilitiesFromSensor(Sensor sensor)109     private static SensorCapabilities createSensorCapabilitiesFromSensor(Sensor sensor) {
110         return SensorCapabilities.newBuilder()
111                 .setType(sensor.getType())
112                 .setName(sensor.getName())
113                 .setVendor(sensor.getVendor())
114                 .setMaxRange(sensor.getMaximumRange())
115                 .setResolution(sensor.getResolution())
116                 .setPower(sensor.getPower())
117                 .setMinDelayUs(sensor.getMinDelay())
118                 .setMaxDelayUs(sensor.getMaxDelay())
119                 .setIsWakeUpSensor(sensor.isWakeUpSensor())
120                 .setReportingMode(sensor.getReportingMode())
121                 .setIsAdditionalInfoSupported(sensor.isAdditionalInfoSupported())
122                 .build();
123     }
124 
processRemoteEvent(RemoteEvent remoteEvent)125     private void processRemoteEvent(RemoteEvent remoteEvent) {
126         if (!remoteEvent.hasSensorConfiguration()) {
127             return;
128         }
129         SensorConfiguration config = remoteEvent.getSensorConfiguration();
130         Sensor sensor = mSensorManager.getDefaultSensor(config.getSensorType());
131         if (sensor == null) {
132             return;
133         }
134         if (config.getEnabled()) {
135             mSensorManager.registerListener(
136                     mSensorEventCallback,
137                     sensor,
138                     config.getSamplingPeriodUs(),
139                     config.getBatchReportingLatencyUs(),
140                     mHandler);
141         } else {
142             mSensorManager.unregisterListener(mSensorEventCallback, sensor);
143         }
144     }
145 }
146