1 /*
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
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.util.sensors;
18 
19 import android.content.Context;
20 import android.hardware.HardwareBuffer;
21 import android.hardware.Sensor;
22 import android.hardware.SensorAdditionalInfo;
23 import android.hardware.SensorDirectChannel;
24 import android.hardware.SensorEvent;
25 import android.hardware.SensorEventListener;
26 import android.hardware.SensorManager;
27 import android.hardware.TriggerEventListener;
28 import android.os.Handler;
29 import android.os.MemoryFile;
30 import android.os.SystemClock;
31 import android.util.ArraySet;
32 
33 import java.lang.reflect.Constructor;
34 import java.lang.reflect.Field;
35 import java.lang.reflect.Method;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.Objects;
40 import java.util.stream.Collectors;
41 
42 import javax.annotation.Nullable;
43 
44 /**
45  * Rudimentary fake for SensorManager
46  *
47  * Currently only supports proximity, light and tap sensors.
48  *
49  * Note that this class ignores the "Handler" argument, so the test is responsible for calling the
50  * listener on the right thread.
51  */
52 public class FakeSensorManager extends SensorManager {
53 
54     public static final String TAP_SENSOR_TYPE = "tapSensorType";
55 
56     private final FakeProximitySensor mFakeProximitySensor;
57     private final FakeGenericSensor mFakeLightSensor;
58     private final FakeGenericSensor mFakeLightSensor2;
59     private final FakeGenericSensor mFakeTapSensor;
60     private final FakeGenericSensor[] mSensors;
61 
FakeSensorManager(Context context)62     public FakeSensorManager(Context context) throws Exception {
63         Sensor proxSensor = context.getSystemService(SensorManager.class)
64                 .getDefaultSensor(Sensor.TYPE_PROXIMITY, true);
65         if (proxSensor == null) {
66             // No prox? Let's create a fake one!
67             proxSensor =
68                     createSensor(Sensor.TYPE_PROXIMITY, null, 1 /* SENSOR_FLAG_WAKE_UP_SENSOR */);
69         }
70 
71         mSensors = new FakeGenericSensor[]{
72                 mFakeProximitySensor = new FakeProximitySensor(proxSensor),
73                 mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)),
74                 mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE)),
75                 mFakeLightSensor2 = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null))
76         };
77     }
78 
getFakeProximitySensor()79     public FakeProximitySensor getFakeProximitySensor() {
80         return mFakeProximitySensor;
81     }
82 
getFakeLightSensor()83     public FakeGenericSensor getFakeLightSensor() {
84         return mFakeLightSensor;
85     }
86 
getFakeLightSensor2()87     public FakeGenericSensor getFakeLightSensor2() {
88         return mFakeLightSensor2;
89     }
90 
getFakeTapSensor()91     public FakeGenericSensor getFakeTapSensor() {
92         return mFakeTapSensor;
93     }
94 
95     @Override
getDefaultSensor(int type)96     public Sensor getDefaultSensor(int type) {
97         Sensor s = super.getDefaultSensor(type);
98         if (s != null) {
99             return s;
100         }
101         // Our mock sensors aren't wakeup, and it's a pain to create them that way. Instead, just
102         // return non-wakeup sensors if we can't find a wakeup sensor.
103         return getDefaultSensor(type, false /* wakeup */);
104     }
105 
106     @Override
getFullSensorList()107     protected List<Sensor> getFullSensorList() {
108         return Arrays
109                 .stream(mSensors)
110                 .map(i -> i.mSensor)
111                 .collect(Collectors.toList());
112     }
113 
114     @Override
getFullDynamicSensorList()115     protected List<Sensor> getFullDynamicSensorList() {
116         return new ArrayList<>();
117     }
118 
119     @Override
unregisterListenerImpl(SensorEventListener listener, Sensor sensor)120     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
121         Objects.requireNonNull(listener);
122         for (FakeGenericSensor s : mSensors) {
123             if (sensor == null || s.mSensor == sensor) {
124                 s.mListeners.remove(listener);
125             }
126         }
127     }
128 
129     @Override
registerListenerImpl(SensorEventListener listener, Sensor sensor, int delayUs, Handler handler, int maxReportLatencyUs, int reservedFlags)130     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
131             int delayUs,
132             Handler handler, int maxReportLatencyUs, int reservedFlags) {
133         Objects.requireNonNull(sensor);
134         Objects.requireNonNull(listener);
135         for (FakeGenericSensor s : mSensors) {
136             if (s.mSensor == sensor) {
137                 s.mListeners.add(listener);
138                 return true;
139             }
140         }
141         return false;
142     }
143 
144     @Override
flushImpl(SensorEventListener listener)145     protected boolean flushImpl(SensorEventListener listener) {
146         return false;
147     }
148 
149     @Override
createDirectChannelImpl(MemoryFile memoryFile, HardwareBuffer hardwareBuffer)150     protected SensorDirectChannel createDirectChannelImpl(MemoryFile memoryFile,
151             HardwareBuffer hardwareBuffer) {
152         return null;
153     }
154 
155     @Override
destroyDirectChannelImpl(SensorDirectChannel channel)156     protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
157 
158     }
159 
160     @Override
configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate)161     protected int configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate) {
162         return 0;
163     }
164 
165     @Override
registerDynamicSensorCallbackImpl(DynamicSensorCallback callback, Handler handler)166     protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
167             Handler handler) {
168 
169     }
170 
171     @Override
unregisterDynamicSensorCallbackImpl( DynamicSensorCallback callback)172     protected void unregisterDynamicSensorCallbackImpl(
173             DynamicSensorCallback callback) {
174 
175     }
176 
177     @Override
requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor)178     protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
179         return true;
180     }
181 
182     @Override
cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, boolean disable)183     protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
184             boolean disable) {
185         return true;
186     }
187 
188     @Override
initDataInjectionImpl(boolean enable, @DataInjectionMode int mode)189     protected boolean initDataInjectionImpl(boolean enable, @DataInjectionMode int mode) {
190         return false;
191     }
192 
193     @Override
injectSensorDataImpl(Sensor sensor, float[] values, int accuracy, long timestamp)194     protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
195             long timestamp) {
196         return false;
197     }
198 
199     @Override
setOperationParameterImpl(SensorAdditionalInfo parameter)200     protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
201         return false;
202     }
203 
createSensor(int type, @Nullable String stringType)204     private Sensor createSensor(int type, @Nullable String stringType) throws Exception {
205         return createSensor(type, stringType, 0 /* flags */);
206     }
207 
createSensor(int type, @Nullable String stringType, int flags)208     private Sensor createSensor(int type, @Nullable String stringType, int flags) throws Exception {
209         Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
210         constr.setAccessible(true);
211         Sensor sensor = constr.newInstance();
212 
213         setSensorType(sensor, type);
214         if (stringType != null) {
215             setSensorField(sensor, "mStringType", stringType);
216         }
217         setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
218         setSensorField(sensor, "mVendor", "Mock Vendor");
219         setSensorField(sensor, "mVersion", 1);
220         setSensorField(sensor, "mHandle", -1);
221         setSensorField(sensor, "mMaxRange", 10);
222         setSensorField(sensor, "mResolution", 1);
223         setSensorField(sensor, "mPower", 1);
224         setSensorField(sensor, "mMinDelay", 1000);
225         setSensorField(sensor, "mMaxDelay", 1000000000);
226         setSensorField(sensor, "mFlags", flags);
227         setSensorField(sensor, "mId", -1);
228 
229         return sensor;
230     }
231 
setSensorField(Sensor sensor, String fieldName, Object value)232     private void setSensorField(Sensor sensor, String fieldName, Object value) throws Exception {
233         Field field = Sensor.class.getDeclaredField(fieldName);
234         field.setAccessible(true);
235         field.set(sensor, value);
236     }
237 
setSensorType(Sensor sensor, int type)238     private void setSensorType(Sensor sensor, int type) throws Exception {
239         Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
240         setter.setAccessible(true);
241         setter.invoke(sensor, type);
242     }
243 
244     public class FakeProximitySensor extends FakeGenericSensor {
245 
FakeProximitySensor(Sensor sensor)246         private FakeProximitySensor(Sensor sensor) {
247             super(sensor);
248         }
249 
sendProximityResult(boolean far)250         public void sendProximityResult(boolean far) {
251             sendSensorEvent(far ? getSensor().getMaximumRange() : 0);
252         }
253     }
254 
255     public class FakeGenericSensor {
256 
257         private final Sensor mSensor;
258         private final ArraySet<SensorEventListener> mListeners = new ArraySet<>();
259 
FakeGenericSensor( Sensor sensor)260         public FakeGenericSensor(
261                 Sensor sensor) {
262             this.mSensor = sensor;
263         }
264 
getSensor()265         public Sensor getSensor() {
266             return mSensor;
267         }
268 
sendSensorEvent(float... values)269         public void sendSensorEvent(float... values) {
270             SensorEvent event = createSensorEvent(values.length);
271             System.arraycopy(values, 0, event.values, 0, values.length);
272             for (SensorEventListener listener : mListeners) {
273                 listener.onSensorChanged(event);
274             }
275         }
276 
createSensorEvent(int valuesSize)277         private SensorEvent createSensorEvent(int valuesSize) {
278             SensorEvent event;
279             try {
280                 Constructor<SensorEvent> constr =
281                         SensorEvent.class.getDeclaredConstructor(Integer.TYPE);
282                 constr.setAccessible(true);
283                 event = constr.newInstance(valuesSize);
284             } catch (Exception e) {
285                 throw new RuntimeException(e);
286             }
287             event.sensor = mSensor;
288             event.timestamp = SystemClock.elapsedRealtimeNanos();
289 
290             return event;
291         }
292     }
293 }
294