blob: 47b3973c4c8f978df3e9b5560ccfab329921f5e1 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cts.helpers;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.Environment;
import android.test.AndroidTestCase;
import android.util.Log;
import java.io.DataOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Set of static helper methods for CTS tests.
*/
public class SensorCtsHelper {
/**
* This is an static class.
*/
private SensorCtsHelper() {}
public static <TValue extends Comparable> TValue get95PercentileValue(
Collection<TValue> collection) {
validateCollection(collection);
ArrayList<TValue> arrayCopy = new ArrayList<TValue>(collection);
Collections.sort(arrayCopy);
// zero-based array index
int arrayIndex = (int)(arrayCopy.size() * 0.95) - 1;
if(arrayIndex < 0) {
arrayIndex = 0;
}
return arrayCopy.get(arrayIndex);
}
// TODO: are there any internal libraries for this?
public static <TValue extends Number> double getMean(Collection<TValue> collection) {
validateCollection(collection);
double sum = 0.0;
for(TValue value : collection) {
sum += value.doubleValue();
}
return sum / collection.size();
}
public static <TValue extends Number> double getVariance(Collection<TValue> collection) {
validateCollection(collection);
double mean = getMean(collection);
ArrayList<Double> squaredDifferences = new ArrayList<Double>();
for(TValue value : collection) {
double difference = mean - value.doubleValue();
squaredDifferences.add(Math.pow(difference, 2));
}
double variance = getMean(squaredDifferences);
return variance;
}
public static <TValue extends Number> double getStandardDeviation(Collection<TValue> collection) {
validateCollection(collection);
double variance = getVariance(collection);
return Math.sqrt(variance);
}
/**
* Gets the jitter values associated with a set of sensor events.
*
* @param events The events to use to obtain the jittering information.
* @param jitterValues The Collection that will contain the computed jitter values.
* @return The mean of the jitter Values.
*/
public static double getJitterMean(TestSensorEvent events[], Collection<Double> jitterValues) {
ArrayList<Long> timestampDelayValues = new ArrayList<Long>();
double averageTimestampDelay = SensorCtsHelper.getAverageTimestampDelayWithValues(events,
timestampDelayValues);
for(long frequency : timestampDelayValues) {
jitterValues.add(Math.abs(averageTimestampDelay - frequency));
}
double jitterMean = SensorCtsHelper.getMean(timestampDelayValues);
return jitterMean;
}
/**
* Gets the frequency values associated with a set of sensor events.
*
* @param events The events to use to obtain the frequency information.
* @param timestampDelayValues The Collection that will contain the computed frequency values.
* @return The mean of the frequency values.
*/
public static double getAverageTimestampDelayWithValues(
TestSensorEvent events[],
Collection<Long> timestampDelayValues) {
for(int i = 1; i < events.length; ++i) {
long previousTimestamp = events[i-1].timestamp;
long timestamp = events[i].timestamp;
timestampDelayValues.add(timestamp - previousTimestamp);
}
double timestampDelayMean = SensorCtsHelper.getMean(timestampDelayValues);
return timestampDelayMean;
}
public static int getSecondsAsMicroSeconds(int seconds) {
return (int) TimeUnit.MICROSECONDS.convert(seconds, TimeUnit.SECONDS);
}
/**
* NOTE:
* - The bug report is usually written to /sdcard/Downloads
* - In order for the test Instrumentation to gather useful data the following permissions are
* required:
* . android.permission.READ_LOGS
* . android.permission.DUMP
*/
public static void collectBugreport(String collectorId)
throws IOException, InterruptedException {
String commands[] = new String[] {
"dumpstate",
"dumpsys",
"logcat -d -v threadtime",
"exit"
};
SimpleDateFormat dateFormat = new SimpleDateFormat("M-d-y_H:m:s.S");
String outputFile = String.format(
"%s/%s_%s",
collectorId,
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
dateFormat.format(new Date()));
DataOutputStream processOutput = null;
try {
Process process = Runtime.getRuntime().exec("/system/bin/sh -");
processOutput = new DataOutputStream(process.getOutputStream());
for(String command : commands) {
processOutput.writeBytes(String.format("%s >> %s\n", command, outputFile));
}
processOutput.flush();
process.waitFor();
Log.d(collectorId, String.format("Bug-Report collected at: %s", outputFile));
} finally {
if(processOutput != null) {
try {
processOutput.close();
} catch(IOException e) {}
}
}
}
public static Sensor getSensor(AndroidTestCase testCase, int sensorType) {
SensorManager sensorManager = (SensorManager)testCase.getContext().getSystemService(
Context.SENSOR_SERVICE);
testCase.assertNotNull(sensorManager);
Sensor sensor = sensorManager.getDefaultSensor(sensorType);
if(sensor == null) {
throw new SensorNotSupportedException(sensorType);
}
return sensor;
}
public static <TReference extends Number> double getFrequencyInHz(TReference samplingRateInUs) {
return 1000000000 / samplingRateInUs.doubleValue();
}
public static String formatAssertionMessage(
String verificationName,
Sensor sensor,
String format,
Object ... params) {
return formatAssertionMessage(verificationName, null, sensor, format, params);
}
public static String formatAssertionMessage(
String verificationName,
SensorTestOperation test,
Sensor sensor,
String format,
Object ... params) {
StringBuilder builder = new StringBuilder();
// identify the verification
builder.append(verificationName);
builder.append("| ");
// add test context information
if(test != null) {
builder.append(test.toString());
builder.append("| ");
}
// add context information
builder.append(
SensorTestInformation.getSensorName(sensor.getType()));
builder.append(", handle:");
builder.append(sensor.getHandle());
builder.append("| ");
// add the custom formatting
builder.append(String.format(format, params));
return builder.toString();
}
/**
* Private helpers
*/
private static void validateCollection(Collection collection) {
if(collection == null || collection.size() == 0) {
throw new IllegalStateException("Collection cannot be null or empty");
}
}
}