1 /*
2  * Copyright (C) 2014 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 android.hardware.cts.helpers;
18 
19 import android.content.Context;
20 import android.hardware.Sensor;
21 import android.hardware.SensorManager;
22 import android.hardware.cts.helpers.sensoroperations.SensorOperation;
23 
24 import java.util.concurrent.TimeUnit;
25 
26 /* TODO: Refactor constructors into a builder */
27 
28 /**
29  * A class that encapsulates base environment information for the {@link SensorOperation}.
30  * The environment is self contained and carries its state around all the sensor test framework.
31  */
32 public class TestSensorEnvironment {
33 
34     /**
35      * It represents the fraction of the expected sampling frequency, at which the sensor can
36      * actually produce events.
37      */
38     private static final float MAXIMUM_EXPECTED_SAMPLING_FREQUENCY_MULTIPLIER = 0.9f;
39 
40     private final Context mContext;
41     private final Sensor mSensor;
42     private final boolean mSensorMightHaveMoreListeners;
43     private final int mSamplingPeriodUs;
44     private final int mMaxReportLatencyUs;
45     private final boolean mIsDeviceSuspendTest;
46     private final boolean mIsIntegrationTest;
47 
48     /**
49      * Constructs an environment for sensor testing.
50      *
51      * @param context The context for the test
52      * @param sensorType The type of the sensor under test
53      * @param samplingPeriodUs The requested collection period for the sensor under test
54      *
55      * @deprecated Use variants with {@link Sensor} objects.
56      */
57     @Deprecated
TestSensorEnvironment(Context context, int sensorType, int samplingPeriodUs)58     public TestSensorEnvironment(Context context, int sensorType, int samplingPeriodUs) {
59         this(context, sensorType, false /* sensorMightHaveMoreListeners */, samplingPeriodUs);
60     }
61 
62     /**
63      * Constructs an environment for sensor testing.
64      *
65      * @param context The context for the test
66      * @param sensorType The type of the sensor under test
67      * @param samplingPeriodUs The requested collection period for the sensor under test
68      * @param maxReportLatencyUs The requested collection report latency for the sensor under test
69      *
70      * @deprecated Use variants with {@link Sensor} objects.
71      */
72     @Deprecated
TestSensorEnvironment( Context context, int sensorType, int samplingPeriodUs, int maxReportLatencyUs)73     public TestSensorEnvironment(
74             Context context,
75             int sensorType,
76             int samplingPeriodUs,
77             int maxReportLatencyUs) {
78         this(context,
79                 sensorType,
80                 false /* sensorMightHaveMoreListeners */,
81                 samplingPeriodUs,
82                 maxReportLatencyUs);
83     }
84 
85     /**
86      * Constructs an environment for sensor testing.
87      *
88      * @param context The context for the test
89      * @param sensorType The type of the sensor under test
90      * @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load
91      * @param samplingPeriodUs The requested collection period for the sensor under test
92      *
93      * @deprecated Use variants with {@link Sensor} objects.
94      */
95     @Deprecated
TestSensorEnvironment( Context context, int sensorType, boolean sensorMightHaveMoreListeners, int samplingPeriodUs)96     public TestSensorEnvironment(
97             Context context,
98             int sensorType,
99             boolean sensorMightHaveMoreListeners,
100             int samplingPeriodUs) {
101         this(context,
102                 sensorType,
103                 sensorMightHaveMoreListeners,
104                 samplingPeriodUs,
105                 0 /* maxReportLatencyUs */);
106     }
107 
108     /**
109      * Constructs an environment for sensor testing.
110      *
111      * @param context The context for the test
112      * @param sensorType The type of the sensor under test
113      * @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load
114      * @param samplingPeriodUs The requested collection period for the sensor under test
115      * @param maxReportLatencyUs The requested collection report latency for the sensor under test
116      *
117      * @deprecated Use variants with {@link Sensor} objects.
118      */
119     @Deprecated
TestSensorEnvironment( Context context, int sensorType, boolean sensorMightHaveMoreListeners, int samplingPeriodUs, int maxReportLatencyUs)120     public TestSensorEnvironment(
121             Context context,
122             int sensorType,
123             boolean sensorMightHaveMoreListeners,
124             int samplingPeriodUs,
125             int maxReportLatencyUs) {
126         this(context,
127                 getSensor(context, sensorType),
128                 sensorMightHaveMoreListeners,
129                 samplingPeriodUs,
130                 maxReportLatencyUs);
131     }
132 
133     /**
134      * Constructs an environment for sensor testing.
135      *
136      * @param context The context for the test
137      * @param sensorType The type of the sensor under test
138      * @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load
139      * @param isIntegrationTest Whether this is an integration test (more than one sensor actived)
140      * @param samplingPeriodUs The requested collection period for the sensor under test
141      * @param maxReportLatencyUs The requested collection report latency for the sensor under test
142      *
143      * @deprecated Use variants with {@link Sensor} objects.
144      */
145     @Deprecated
TestSensorEnvironment( Context context, int sensorType, boolean sensorMightHaveMoreListeners, boolean isIntegrationTest, int samplingPeriodUs, int maxReportLatencyUs)146     public TestSensorEnvironment(
147             Context context,
148             int sensorType,
149             boolean sensorMightHaveMoreListeners,
150             boolean isIntegrationTest,
151             int samplingPeriodUs,
152             int maxReportLatencyUs) {
153         this(context,
154                 getSensor(context, sensorType),
155                 sensorMightHaveMoreListeners,
156                 isIntegrationTest,
157                 samplingPeriodUs,
158                 maxReportLatencyUs);
159     }
160 
161     /**
162      * Constructs an environment for sensor testing.
163      *
164      * @param context The context for the test
165      * @param sensor The sensor under test
166      * @param samplingPeriodUs The requested collection period for the sensor under test
167      * @param maxReportLatencyUs The requested collection report latency for the sensor under test
168      */
TestSensorEnvironment( Context context, Sensor sensor, int samplingPeriodUs, int maxReportLatencyUs)169     public TestSensorEnvironment(
170             Context context,
171             Sensor sensor,
172             int samplingPeriodUs,
173             int maxReportLatencyUs) {
174         this(context,
175                 sensor,
176                 false /* sensorMightHaveMoreListeners */,
177                 samplingPeriodUs,
178                 maxReportLatencyUs);
179     }
180 
181     /**
182      * Constructs an environment for sensor testing.
183      *
184      * @param context The context for the test
185      * @param sensor The sensor under test
186      * @param sensorMightHaveMoreListeners Whether the sensor under test is acting under load (this
187      *                                     usually implies that there are several listeners
188      *                                     requesting different sampling periods)
189      * @param samplingPeriodUs The requested collection period for the sensor under test
190      * @param maxReportLatencyUs The requested collection report latency for the sensor under test
191      */
TestSensorEnvironment( Context context, Sensor sensor, boolean sensorMightHaveMoreListeners, int samplingPeriodUs, int maxReportLatencyUs)192     public TestSensorEnvironment(
193             Context context,
194             Sensor sensor,
195             boolean sensorMightHaveMoreListeners,
196             int samplingPeriodUs,
197             int maxReportLatencyUs) {
198         this(context,
199                 sensor,
200                 sensorMightHaveMoreListeners,
201                 samplingPeriodUs,
202                 maxReportLatencyUs,
203                 false /* isDeviceSuspendTest */);
204     }
205 
TestSensorEnvironment( Context context, Sensor sensor, boolean sensorMightHaveMoreListeners, boolean isIntegrationTest, int samplingPeriodUs, int maxReportLatencyUs)206     public TestSensorEnvironment(
207             Context context,
208             Sensor sensor,
209             boolean sensorMightHaveMoreListeners,
210             boolean isIntegrationTest,
211             int samplingPeriodUs,
212             int maxReportLatencyUs) {
213         this(context,
214                 sensor,
215                 sensorMightHaveMoreListeners,
216                 samplingPeriodUs,
217                 maxReportLatencyUs,
218                 false /* isDeviceSuspendTest */,
219                 isIntegrationTest);
220     }
221 
TestSensorEnvironment( Context context, Sensor sensor, boolean sensorMightHaveMoreListeners, int samplingPeriodUs, int maxReportLatencyUs, boolean isDeviceSuspendTest)222     public TestSensorEnvironment(
223             Context context,
224             Sensor sensor,
225             boolean sensorMightHaveMoreListeners,
226             int samplingPeriodUs,
227             int maxReportLatencyUs,
228             boolean isDeviceSuspendTest) {
229         this(context, sensor, sensorMightHaveMoreListeners,
230                 samplingPeriodUs, maxReportLatencyUs,
231                 isDeviceSuspendTest,
232                 false /* isIntegrationTest */);
233     }
234 
TestSensorEnvironment( Context context, Sensor sensor, boolean sensorMightHaveMoreListeners, int samplingPeriodUs, int maxReportLatencyUs, boolean isDeviceSuspendTest, boolean isIntegrationTest)235     public TestSensorEnvironment(
236             Context context,
237             Sensor sensor,
238             boolean sensorMightHaveMoreListeners,
239             int samplingPeriodUs,
240             int maxReportLatencyUs,
241             boolean isDeviceSuspendTest,
242             boolean isIntegrationTest) {
243         mContext = context;
244         mSensor = sensor;
245         mSensorMightHaveMoreListeners = sensorMightHaveMoreListeners;
246         mSamplingPeriodUs = samplingPeriodUs;
247         mMaxReportLatencyUs = maxReportLatencyUs;
248         mIsDeviceSuspendTest = isDeviceSuspendTest;
249         mIsIntegrationTest = isIntegrationTest;
250     }
251 
252     /**
253      * @return The context instance associated with the test.
254      */
getContext()255     public Context getContext() {
256         return mContext;
257     }
258 
259     /**
260      * @return The sensor under test.
261      */
getSensor()262     public Sensor getSensor() {
263         return mSensor;
264     }
265 
266     /**
267      * @return The requested collection rate in microseconds.
268      */
getRequestedSamplingPeriodUs()269     public int getRequestedSamplingPeriodUs() {
270         return mSamplingPeriodUs;
271     }
272 
273     /**
274      * @return The frequency equivalent to {@link #getRequestedSamplingPeriodUs()}.
275      */
getFrequencyHz()276     public double getFrequencyHz() {
277         return SensorCtsHelper.getFrequency(mSamplingPeriodUs, TimeUnit.MICROSECONDS);
278     }
279 
280     /**
281      * @return A string representing the frequency equivalent to
282      * {@link #getRequestedSamplingPeriodUs()}.
283      */
getFrequencyString()284     public String getFrequencyString() {
285         if (mSamplingPeriodUs == SensorManager.SENSOR_DELAY_FASTEST) {
286             return "fastest";
287         }
288         return String.format("%.2fhz", getFrequencyHz());
289     }
290 
291     /**
292      * @return The requested collection max batch report latency in microseconds.
293      */
getMaxReportLatencyUs()294     public int getMaxReportLatencyUs() {
295         return mMaxReportLatencyUs;
296     }
297 
298     /**
299      * Returns {@code true} if there might be other listeners of {@link #getSensor()} requesting
300      * data at different sampling rates (the rates are unknown); false otherwise.
301      */
isSensorSamplingRateOverloaded()302     public boolean isSensorSamplingRateOverloaded() {
303         return mSensorMightHaveMoreListeners
304                 && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_FASTEST;
305     }
306 
307     /**
308      * Convert the {@link #getRequestedSamplingPeriodUs()} into delay in microseconds.
309      * <p>
310      * The flags SensorManager.SENSOR_DELAY_[GAME|UI|NORMAL] are not supported since the CDD does
311      * not specify values for these flags. The rate is set to the max of
312      * {@link Sensor#getMinDelay()} and the rate given.
313      * </p>
314      */
getExpectedSamplingPeriodUs()315     public int getExpectedSamplingPeriodUs() {
316         if (!isDelayRateTestable()) {
317             throw new IllegalArgumentException("rateUs cannot be SENSOR_DELAY_[GAME|UI|NORMAL]");
318         }
319 
320         int expectedSamplingPeriodUs = mSamplingPeriodUs;
321         int sensorMaxDelay = mSensor.getMaxDelay();
322         if (sensorMaxDelay > 0) {
323             expectedSamplingPeriodUs = Math.min(expectedSamplingPeriodUs, sensorMaxDelay);
324         }
325 
326         return Math.max(expectedSamplingPeriodUs, mSensor.getMinDelay());
327     }
328 
329     /**
330      * Calculate the maximum expected sampling period in us.
331      * @return The maximum acceptable actual sampling period of this sensor.
332      *         For continuous sensors, this is higher than {@link #getExpectedSamplingPeriodUs()}
333      *         because sensors are allowed to run up to 10% slower than requested.
334      *         For sensors with other reporting modes, this is the maximum integer
335      *         {@link Integer#MAX_VALUE} as they can report no events for long
336      *         periods of time.
337      */
getMaximumExpectedSamplingPeriodUs()338     public int getMaximumExpectedSamplingPeriodUs() {
339         int sensorReportingMode = mSensor.getReportingMode();
340         if (sensorReportingMode != Sensor.REPORTING_MODE_CONTINUOUS) {
341             return Integer.MAX_VALUE;
342         }
343 
344         int expectedSamplingPeriodUs = getExpectedSamplingPeriodUs();
345         return (int) (expectedSamplingPeriodUs / MAXIMUM_EXPECTED_SAMPLING_FREQUENCY_MULTIPLIER);
346     }
347 
348 
349     /**
350      * Calculate the allowed sensor start delay.
351      *
352      * CDD Section 7.3:
353      * MUST report the first sensor sample within 400 milliseconds + 2 * sample_time of the
354      * sensor being activated. It is acceptable for this sample to have an accuracy of 0.
355      *
356      * [CDD] Keep this updated with CDD.
357      */
getAllowedSensorStartDelay()358     public long getAllowedSensorStartDelay() {
359         return TimeUnit.MILLISECONDS.toMicros(400) + 2 * getMaximumExpectedSamplingPeriodUs();
360     }
361 
362     /**
363      * @return The number of axes in the coordinate system of the sensor under test.
364      */
getSensorAxesCount()365     public int getSensorAxesCount() {
366         switch (mSensor.getType()) {
367             case Sensor.TYPE_GYROSCOPE:
368                 return 3;
369             default:
370                 throw new IllegalStateException("Axes count needs to be defined for sensor type: "
371                         + mSensor.getStringType());
372         }
373     }
374 
375     /**
376      * Get the default sensor for a given type.
377      *
378      * @deprecated Used for historical reasons, sensor tests must be written around Sensor objects,
379      * so all sensors of a given type are exercised.
380      */
381     @Deprecated
getSensor(Context context, int sensorType)382     public static Sensor getSensor(Context context, int sensorType) {
383         SensorManager sensorManager =
384                 (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
385         if (sensorManager == null) {
386             throw new IllegalStateException("SensorService is not present in the system.");
387         }
388 
389         Sensor sensor = sensorManager.getDefaultSensor(sensorType);
390         if(sensor == null) {
391             throw new SensorNotSupportedException(sensorType);
392         }
393         return sensor;
394     }
395 
396     /**
397      * @return The maximum latency of a given sensor, on top of {@link #getMaxReportLatencyUs()}.
398      *
399      * NOTE: The latency is defined as the time between the event happens and the time the event is
400      * generated.
401      *
402      * - At time event_time (reported in the sensor event), the physical event happens
403      * - At time event_time + detection_latency, the physical event is detected and the event is
404      *   saved in the hardware fifo
405      * - At time event_time + detection_latency + report_latency, the event is reported through the
406      *   HAL
407      *
408      * Soon after that, the event is piped through the framework to the application. This time may
409      * vary depending on the CPU load. The time 'detection_latency' must be less than
410      * {@link #getSensorMaxDetectionLatencyNs(Sensor)}, and 'report_latency' must be less than
411      * {@link #getMaxReportLatencyUs()} passed through batch() at the HAL level.
412      */
413     // TODO: when all tests are moved to use the Sensor test framework, make this method non-static
getSensorMaxDetectionLatencyNs(Sensor sensor)414     public static long getSensorMaxDetectionLatencyNs(Sensor sensor) {
415         int reportLatencySec;
416         switch (sensor.getType()) {
417             case Sensor.TYPE_STEP_DETECTOR:
418                 reportLatencySec = 2;
419                 break;
420             case Sensor.TYPE_STEP_COUNTER:
421                 reportLatencySec = 10;
422                 break;
423             case Sensor.TYPE_SIGNIFICANT_MOTION:
424                 reportLatencySec = 10;
425                 break;
426             default:
427                 reportLatencySec = 0;
428         }
429         return TimeUnit.SECONDS.toNanos(reportLatencySec);
430     }
431 
432     @Override
toString()433     public String toString() {
434         return String.format(
435                 "Sensor='%s', SamplingRateOverloaded=%s, SamplingPeriod=%sus, "
436                         + "MaxReportLatency=%sus",
437                 mSensor,
438                 isSensorSamplingRateOverloaded(),
439                 mSamplingPeriodUs,
440                 mMaxReportLatencyUs);
441     }
442 
443     /**
444      * Return true if {@link #getRequestedSamplingPeriodUs()} is not one of
445      * {@link SensorManager#SENSOR_DELAY_GAME}, {@link SensorManager#SENSOR_DELAY_UI}, or
446      * {@link SensorManager#SENSOR_DELAY_NORMAL}.
447      */
isDelayRateTestable()448     private boolean isDelayRateTestable() {
449         return (mSamplingPeriodUs >= 0
450                 && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_GAME
451                 && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_UI
452                 && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_NORMAL);
453     }
454 
isDeviceSuspendTest()455     public boolean isDeviceSuspendTest() {
456         return mIsDeviceSuspendTest;
457     }
458 
isIntegrationTest()459     public boolean isIntegrationTest() {
460         return mIsIntegrationTest;
461     }
462 }
463 
464