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
17package com.android.systemui.utils.hardware;
18
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
33import com.google.android.collect.Lists;
34
35import java.lang.reflect.Constructor;
36import java.lang.reflect.Field;
37import java.lang.reflect.Method;
38import java.util.ArrayList;
39import java.util.List;
40
41/**
42 * Rudimentary fake for SensorManager
43 *
44 * Currently only supports the proximity sensor.
45 *
46 * Note that this class ignores the "Handler" argument, so the test is responsible for calling the
47 * listener on the right thread.
48 */
49public class FakeSensorManager extends SensorManager {
50
51    private final MockProximitySensor mMockProximitySensor;
52
53    public FakeSensorManager(Context context) throws Exception {
54        Sensor proxSensor = context.getSystemService(SensorManager.class)
55                .getDefaultSensor(Sensor.TYPE_PROXIMITY);
56        if (proxSensor == null) {
57            // No prox? Let's create a fake one!
58            proxSensor = createSensor(Sensor.TYPE_PROXIMITY);
59        }
60        mMockProximitySensor = new MockProximitySensor(proxSensor);
61    }
62
63    public MockProximitySensor getMockProximitySensor() {
64        return mMockProximitySensor;
65    }
66
67    @Override
68    public Sensor getDefaultSensor(int type) {
69        Sensor s = super.getDefaultSensor(type);
70        if (s != null) {
71            return s;
72        }
73        // Our mock sensors aren't wakeup, and it's a pain to create them that way. Instead, just
74        // return non-wakeup sensors if we can't find a wakeup sensor.
75        return getDefaultSensor(type, false /* wakeup */);
76    }
77
78    @Override
79    protected List<Sensor> getFullSensorList() {
80        return Lists.newArrayList(mMockProximitySensor.sensor);
81    }
82
83    @Override
84    protected List<Sensor> getFullDynamicSensorList() {
85        return new ArrayList<>();
86    }
87
88    @Override
89    protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
90        if (sensor == mMockProximitySensor.sensor || sensor == null) {
91            mMockProximitySensor.listeners.remove(listener);
92        }
93    }
94
95    @Override
96    protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
97            int delayUs,
98            Handler handler, int maxReportLatencyUs, int reservedFlags) {
99        if (sensor == mMockProximitySensor.sensor) {
100            mMockProximitySensor.listeners.add(listener);
101            return true;
102        }
103        return false;
104    }
105
106    @Override
107    protected boolean flushImpl(SensorEventListener listener) {
108        return false;
109    }
110
111    @Override
112    protected SensorDirectChannel createDirectChannelImpl(MemoryFile memoryFile,
113            HardwareBuffer hardwareBuffer) {
114        return null;
115    }
116
117    @Override
118    protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
119
120    }
121
122    @Override
123    protected int configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate) {
124        return 0;
125    }
126
127    @Override
128    protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
129            Handler handler) {
130
131    }
132
133    @Override
134    protected void unregisterDynamicSensorCallbackImpl(
135            DynamicSensorCallback callback) {
136
137    }
138
139    @Override
140    protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
141        return false;
142    }
143
144    @Override
145    protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
146            boolean disable) {
147        return false;
148    }
149
150    @Override
151    protected boolean initDataInjectionImpl(boolean enable) {
152        return false;
153    }
154
155    @Override
156    protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
157            long timestamp) {
158        return false;
159    }
160
161    @Override
162    protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
163        return false;
164    }
165
166    private Sensor createSensor(int type) throws Exception {
167        Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
168        constr.setAccessible(true);
169        Sensor sensor = constr.newInstance();
170
171        setSensorType(sensor, type);
172        setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
173        setSensorField(sensor, "mVendor", "Mock Vendor");
174        setSensorField(sensor, "mVersion", 1);
175        setSensorField(sensor, "mHandle", -1);
176        setSensorField(sensor, "mMaxRange", 10);
177        setSensorField(sensor, "mResolution", 1);
178        setSensorField(sensor, "mPower", 1);
179        setSensorField(sensor, "mMinDelay", 1000);
180        setSensorField(sensor, "mMaxDelay", 1000000000);
181        setSensorField(sensor, "mFlags", 0);
182        setSensorField(sensor, "mId", -1);
183
184        return sensor;
185    }
186
187    private void setSensorField(Sensor sensor, String fieldName, Object value) throws Exception {
188        Field field = Sensor.class.getDeclaredField(fieldName);
189        field.setAccessible(true);
190        field.set(sensor, value);
191    }
192
193    private void setSensorType(Sensor sensor, int type) throws Exception {
194        Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
195        setter.setAccessible(true);
196        setter.invoke(sensor, type);
197    }
198
199    public class MockProximitySensor {
200        final Sensor sensor;
201        final ArraySet<SensorEventListener> listeners = new ArraySet<>();
202
203        private MockProximitySensor(Sensor sensor) {
204            this.sensor = sensor;
205        }
206
207        public void sendProximityResult(boolean far) {
208            SensorEvent event = createSensorEvent(1);
209            event.values[0] = far ? sensor.getMaximumRange() : 0;
210            for (SensorEventListener listener : listeners) {
211                listener.onSensorChanged(event);
212            }
213        }
214
215        private SensorEvent createSensorEvent(int valuesSize) {
216            SensorEvent event;
217            try {
218                Constructor<SensorEvent> constr =
219                        SensorEvent.class.getDeclaredConstructor(Integer.TYPE);
220                constr.setAccessible(true);
221                event = constr.newInstance(valuesSize);
222            } catch (Exception e) {
223                throw new RuntimeException(e);
224            }
225            event.sensor = sensor;
226            event.timestamp = SystemClock.elapsedRealtimeNanos();
227
228            return event;
229        }
230    }
231}
232