blob: 0bc7868aab9cc792833162c45a2f1380ff783173 [file] [log] [blame]
Adrian Roosd35d4ca2017-04-19 14:31:03 -07001/*
2 * Copyright (C) 2017 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
Dave Mankoff63a12822019-09-16 14:38:06 -040014 * limitations under the License.
Adrian Roosd35d4ca2017-04-19 14:31:03 -070015 */
16
Dave Mankoff63a12822019-09-16 14:38:06 -040017package com.android.systemui.util.sensors;
Adrian Roosd35d4ca2017-04-19 14:31:03 -070018
19import android.content.Context;
20import android.hardware.HardwareBuffer;
21import android.hardware.Sensor;
22import android.hardware.SensorAdditionalInfo;
23import android.hardware.SensorDirectChannel;
24import android.hardware.SensorEvent;
25import android.hardware.SensorEventListener;
26import android.hardware.SensorManager;
27import android.hardware.TriggerEventListener;
28import android.os.Handler;
29import android.os.MemoryFile;
30import android.os.SystemClock;
31import android.util.ArraySet;
32
Adrian Roos2981eb02017-05-26 18:40:09 -070033import com.android.internal.util.Preconditions;
Adrian Roosd35d4ca2017-04-19 14:31:03 -070034
35import java.lang.reflect.Constructor;
Adrian Roos84a187f2017-04-28 14:10:51 -070036import java.lang.reflect.Field;
37import java.lang.reflect.Method;
Adrian Roosd35d4ca2017-04-19 14:31:03 -070038import java.util.ArrayList;
Adrian Roos2981eb02017-05-26 18:40:09 -070039import java.util.Arrays;
Adrian Roosd35d4ca2017-04-19 14:31:03 -070040import java.util.List;
Adrian Roos2981eb02017-05-26 18:40:09 -070041import java.util.stream.Collectors;
Adrian Roosd35d4ca2017-04-19 14:31:03 -070042
Lucas Dupin3174c662019-07-15 15:49:54 -070043import javax.annotation.Nullable;
44
Adrian Roosd35d4ca2017-04-19 14:31:03 -070045/**
46 * Rudimentary fake for SensorManager
47 *
Lucas Dupin3174c662019-07-15 15:49:54 -070048 * Currently only supports proximity, light and tap sensors.
Adrian Roosd35d4ca2017-04-19 14:31:03 -070049 *
50 * Note that this class ignores the "Handler" argument, so the test is responsible for calling the
51 * listener on the right thread.
52 */
Adrian Roos84a187f2017-04-28 14:10:51 -070053public class FakeSensorManager extends SensorManager {
Adrian Roosd35d4ca2017-04-19 14:31:03 -070054
Lucas Dupin3174c662019-07-15 15:49:54 -070055 public static final String TAP_SENSOR_TYPE = "tapSensorType";
56
Dave Mankoff63a12822019-09-16 14:38:06 -040057 private final FakeProximitySensor mFakeProximitySensor;
Adrian Roos2981eb02017-05-26 18:40:09 -070058 private final FakeGenericSensor mFakeLightSensor;
Lucas Dupin3174c662019-07-15 15:49:54 -070059 private final FakeGenericSensor mFakeTapSensor;
Adrian Roos2981eb02017-05-26 18:40:09 -070060 private final FakeGenericSensor[] mSensors;
Adrian Roosd35d4ca2017-04-19 14:31:03 -070061
Adrian Roos84a187f2017-04-28 14:10:51 -070062 public FakeSensorManager(Context context) throws Exception {
63 Sensor proxSensor = context.getSystemService(SensorManager.class)
64 .getDefaultSensor(Sensor.TYPE_PROXIMITY);
65 if (proxSensor == null) {
66 // No prox? Let's create a fake one!
Lucas Dupin3174c662019-07-15 15:49:54 -070067 proxSensor = createSensor(Sensor.TYPE_PROXIMITY, null);
Adrian Roos84a187f2017-04-28 14:10:51 -070068 }
Adrian Roos2981eb02017-05-26 18:40:09 -070069
70 mSensors = new FakeGenericSensor[]{
Dave Mankoff63a12822019-09-16 14:38:06 -040071 mFakeProximitySensor = new FakeProximitySensor(proxSensor),
Lucas Dupin3174c662019-07-15 15:49:54 -070072 mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)),
73 mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE))
Adrian Roos2981eb02017-05-26 18:40:09 -070074 };
Adrian Roos84a187f2017-04-28 14:10:51 -070075 }
76
Dave Mankoff63a12822019-09-16 14:38:06 -040077 public FakeProximitySensor getFakeProximitySensor() {
78 return mFakeProximitySensor;
Adrian Roos84a187f2017-04-28 14:10:51 -070079 }
80
Adrian Roos2981eb02017-05-26 18:40:09 -070081 public FakeGenericSensor getFakeLightSensor() {
82 return mFakeLightSensor;
83 }
84
Lucas Dupin3174c662019-07-15 15:49:54 -070085 public FakeGenericSensor getFakeTapSensor() {
86 return mFakeTapSensor;
87 }
88
Adrian Roos84a187f2017-04-28 14:10:51 -070089 @Override
90 public Sensor getDefaultSensor(int type) {
91 Sensor s = super.getDefaultSensor(type);
92 if (s != null) {
93 return s;
94 }
Dave Mankoffd94c9692019-10-18 12:38:21 -040095 switch(type) {
96 case Sensor.TYPE_PROXIMITY:
97 try {
98 return createSensor(Sensor.TYPE_PROXIMITY, null);
99 } catch (Exception e) {
100 // fall through
101 }
102 break;
103 default:
104 break;
105
106 }
Adrian Roos84a187f2017-04-28 14:10:51 -0700107 // Our mock sensors aren't wakeup, and it's a pain to create them that way. Instead, just
108 // return non-wakeup sensors if we can't find a wakeup sensor.
109 return getDefaultSensor(type, false /* wakeup */);
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700110 }
111
112 @Override
113 protected List<Sensor> getFullSensorList() {
Adrian Roos2981eb02017-05-26 18:40:09 -0700114 return Arrays
115 .stream(mSensors)
116 .map(i -> i.mSensor)
117 .collect(Collectors.toList());
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700118 }
119
120 @Override
121 protected List<Sensor> getFullDynamicSensorList() {
122 return new ArrayList<>();
123 }
124
125 @Override
126 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
Adrian Roos2981eb02017-05-26 18:40:09 -0700127 Preconditions.checkNotNull(listener);
128 for (FakeGenericSensor s : mSensors) {
129 if (sensor == null || s.mSensor == sensor) {
130 s.mListeners.remove(listener);
131 }
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700132 }
133 }
134
135 @Override
136 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
137 int delayUs,
138 Handler handler, int maxReportLatencyUs, int reservedFlags) {
Adrian Roos2981eb02017-05-26 18:40:09 -0700139 Preconditions.checkNotNull(sensor);
140 Preconditions.checkNotNull(listener);
141 for (FakeGenericSensor s : mSensors) {
142 if (s.mSensor == sensor) {
143 s.mListeners.add(listener);
144 return true;
145 }
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700146 }
147 return false;
148 }
149
150 @Override
151 protected boolean flushImpl(SensorEventListener listener) {
152 return false;
153 }
154
155 @Override
156 protected SensorDirectChannel createDirectChannelImpl(MemoryFile memoryFile,
157 HardwareBuffer hardwareBuffer) {
158 return null;
159 }
160
161 @Override
162 protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
163
164 }
165
166 @Override
167 protected int configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate) {
168 return 0;
169 }
170
171 @Override
172 protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
173 Handler handler) {
174
175 }
176
177 @Override
178 protected void unregisterDynamicSensorCallbackImpl(
179 DynamicSensorCallback callback) {
180
181 }
182
183 @Override
184 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
Lucas Dupin3174c662019-07-15 15:49:54 -0700185 return true;
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700186 }
187
188 @Override
189 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
190 boolean disable) {
Lucas Dupin3174c662019-07-15 15:49:54 -0700191 return true;
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700192 }
193
194 @Override
195 protected boolean initDataInjectionImpl(boolean enable) {
196 return false;
197 }
198
199 @Override
200 protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
201 long timestamp) {
202 return false;
203 }
204
205 @Override
206 protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
207 return false;
208 }
209
Lucas Dupin3174c662019-07-15 15:49:54 -0700210 private Sensor createSensor(int type, @Nullable String stringType) throws Exception {
Adrian Roos84a187f2017-04-28 14:10:51 -0700211 Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
212 constr.setAccessible(true);
213 Sensor sensor = constr.newInstance();
214
215 setSensorType(sensor, type);
Lucas Dupin3174c662019-07-15 15:49:54 -0700216 if (stringType != null) {
217 setSensorField(sensor, "mStringType", stringType);
218 }
Adrian Roos84a187f2017-04-28 14:10:51 -0700219 setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
220 setSensorField(sensor, "mVendor", "Mock Vendor");
221 setSensorField(sensor, "mVersion", 1);
222 setSensorField(sensor, "mHandle", -1);
223 setSensorField(sensor, "mMaxRange", 10);
224 setSensorField(sensor, "mResolution", 1);
225 setSensorField(sensor, "mPower", 1);
226 setSensorField(sensor, "mMinDelay", 1000);
227 setSensorField(sensor, "mMaxDelay", 1000000000);
228 setSensorField(sensor, "mFlags", 0);
229 setSensorField(sensor, "mId", -1);
230
231 return sensor;
232 }
233
234 private void setSensorField(Sensor sensor, String fieldName, Object value) throws Exception {
235 Field field = Sensor.class.getDeclaredField(fieldName);
236 field.setAccessible(true);
237 field.set(sensor, value);
238 }
239
240 private void setSensorType(Sensor sensor, int type) throws Exception {
241 Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
242 setter.setAccessible(true);
243 setter.invoke(sensor, type);
244 }
245
Dave Mankoff63a12822019-09-16 14:38:06 -0400246 public class FakeProximitySensor extends FakeGenericSensor {
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700247
Dave Mankoff63a12822019-09-16 14:38:06 -0400248 private FakeProximitySensor(Sensor sensor) {
Adrian Roos2981eb02017-05-26 18:40:09 -0700249 super(sensor);
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700250 }
251
252 public void sendProximityResult(boolean far) {
Adrian Roos2981eb02017-05-26 18:40:09 -0700253 sendSensorEvent(far ? getSensor().getMaximumRange() : 0);
254 }
255 }
256
257 public class FakeGenericSensor {
258
259 private final Sensor mSensor;
260 private final ArraySet<SensorEventListener> mListeners = new ArraySet<>();
261
262 public FakeGenericSensor(
263 Sensor sensor) {
264 this.mSensor = sensor;
265 }
266
267 public Sensor getSensor() {
268 return mSensor;
269 }
270
271 public void sendSensorEvent(float... values) {
272 SensorEvent event = createSensorEvent(values.length);
273 System.arraycopy(values, 0, event.values, 0, values.length);
274 for (SensorEventListener listener : mListeners) {
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700275 listener.onSensorChanged(event);
276 }
277 }
278
279 private SensorEvent createSensorEvent(int valuesSize) {
280 SensorEvent event;
281 try {
282 Constructor<SensorEvent> constr =
283 SensorEvent.class.getDeclaredConstructor(Integer.TYPE);
284 constr.setAccessible(true);
285 event = constr.newInstance(valuesSize);
286 } catch (Exception e) {
287 throw new RuntimeException(e);
288 }
Adrian Roos2981eb02017-05-26 18:40:09 -0700289 event.sensor = mSensor;
Adrian Roosd35d4ca2017-04-19 14:31:03 -0700290 event.timestamp = SystemClock.elapsedRealtimeNanos();
291
292 return event;
293 }
294 }
295}