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