Home | History | Annotate | Download | only in sensors
      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 com.android.cts.verifier.sensors;
     18 
     19 import com.android.cts.verifier.R;
     20 import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
     21 import com.android.cts.verifier.sensors.renderers.GLArrowSensorTestRenderer;
     22 
     23 import junit.framework.Assert;
     24 
     25 import android.content.Context;
     26 import android.hardware.Sensor;
     27 import android.hardware.SensorEvent;
     28 import android.hardware.SensorEventListener;
     29 import android.hardware.SensorManager;
     30 import android.hardware.cts.helpers.SensorNotSupportedException;
     31 import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
     32 import android.os.Bundle;
     33 import android.util.Log;
     34 
     35 import java.util.concurrent.TimeUnit;
     36 
     37 /**
     38  * This test verifies that mobile device can detect it's orientation in space and after device
     39  * movement in space it correctly detects original (reference) position.
     40  * All three rotation vectors are tested:
     41  * - ROTATION_VECTOR,
     42  * - GEOMAGNETIC_ROTATION_VECTOR,
     43  * - GAME_ROTATION_VECTOR.
     44  */
     45 public class RotationVectorTestActivity
     46         extends SensorCtsVerifierTestActivity
     47         implements SensorEventListener {
     48     public RotationVectorTestActivity() {
     49         super(RotationVectorTestActivity.class);
     50     }
     51 
     52     private SensorManager mSensorManager;
     53     private SensorEventListener mListener;
     54 
     55     /**
     56      * Defines the thresholds for each rotation vector in degrees.
     57      */
     58     private static final double[] MAX_DEVIATION_DEGREES = {
     59         10.0, // ROTATION_VECTOR
     60         10.0, // GEOMAGNETIC ROTATION_VECTOR
     61         40.0, // GAME_ROTATION_VECTOR
     62     };
     63 
     64     private static final int MAX_SENSORS_AVAILABLE = 3;
     65     private static final int ROTATION_VECTOR_INDEX = 0;
     66     private static final int GEOMAGNETIC_ROTATION_VECTOR_INDEX = 1;
     67     private static final int GAME_ROTATION_VECTOR_INDEX = 2;
     68 
     69     private float[][] mLastEvent = new float[3][5];
     70     private final float[][] mReference = new float[3][16];
     71     private final float[][] mAngularChange = new float[3][3];
     72     private final Sensor[] mSensor = new Sensor[3];
     73 
     74     /**
     75      * The activity setup collects all the required data for test cases.
     76      * This approach allows to test all sensors at once.
     77      */
     78     @Override
     79     protected void activitySetUp() throws InterruptedException {
     80         if (mSensor[ROTATION_VECTOR_INDEX] == null
     81                 && mSensor[GEOMAGNETIC_ROTATION_VECTOR_INDEX] == null
     82                 && mSensor[GAME_ROTATION_VECTOR_INDEX] == null) {
     83             // if none of the sensors is supported, skip the test by throwing an exception
     84             throw new SensorTestStateNotSupportedException("Rotation vectors are not supported.");
     85         }
     86 
     87         // TODO: take reference value automatically when device is 'still'
     88         clearText();
     89         appendText(R.string.snsr_rotation_vector_set_reference);
     90         waitForUserToContinue();
     91 
     92         clearText();
     93         for (int i = 0; i < MAX_SENSORS_AVAILABLE; ++i) {
     94             SensorManager.getRotationMatrixFromVector(mReference[i], mLastEvent[i].clone());
     95         }
     96 
     97         // TODO: check the user actually moved the device during the test
     98         appendText(R.string.snsr_rotation_vector_reference_set);
     99         appendText(R.string.snsr_rotation_vector_move_info);
    100         appendText(R.string.snsr_test_play_sound);
    101         Thread.sleep(TimeUnit.SECONDS.toMillis(30));
    102         playSound();
    103 
    104         // TODO: take final value automatically when device becomes 'still' at the end
    105         clearText();
    106         appendText(R.string.snsr_rotation_vector_set_final);
    107         waitForUserToContinue();
    108 
    109         clearText();
    110         closeGlSurfaceView();
    111 
    112         float[] finalVector = new float[16];
    113         for (int i = 0; i < MAX_SENSORS_AVAILABLE; ++i) {
    114             SensorManager.getRotationMatrixFromVector(finalVector, mLastEvent[i].clone());
    115             SensorManager.getAngleChange(mAngularChange[i], mReference[i], finalVector);
    116         }
    117     }
    118 
    119     /**
    120      * Verifies that a given 'Rotation Vector' sensor does not drift over time.
    121      * The test takes in consideration a reference measurement, and a final measurement. It then
    122      * calculates its angular change.
    123      */
    124     private String verifyVector(int sensorIndex, int sensorType)
    125             throws Throwable {
    126         Sensor sensor = mSensor[sensorIndex];
    127         if (sensor == null) {
    128             throw new SensorNotSupportedException(sensorType);
    129         }
    130 
    131         float[] angularChange = mAngularChange[sensorIndex];
    132         double maxDeviationDegrees = MAX_DEVIATION_DEGREES[sensorIndex];
    133         double maxComponentDegrees = findMaxComponentDegrees(angularChange);
    134         String message = getString(
    135                 R.string.snsr_rotation_vector_verification,
    136                 Math.toDegrees(angularChange[0]),
    137                 Math.toDegrees(angularChange[1]),
    138                 Math.toDegrees(angularChange[2]),
    139                 maxComponentDegrees,
    140                 maxDeviationDegrees);
    141 
    142         Assert.assertEquals(message, 0, maxComponentDegrees, maxDeviationDegrees);
    143         return message;
    144     }
    145 
    146     /**
    147      * Test cases.
    148      */
    149     public String testRotationVector() throws Throwable {
    150         return verifyVector(ROTATION_VECTOR_INDEX, Sensor.TYPE_ROTATION_VECTOR);
    151     }
    152 
    153     public String testGeomagneticRotationVector() throws Throwable {
    154         return verifyVector(
    155                 GEOMAGNETIC_ROTATION_VECTOR_INDEX,
    156                 Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
    157     }
    158 
    159     public String testGameRotationVector() throws Throwable {
    160         return verifyVector(GAME_ROTATION_VECTOR_INDEX, Sensor.TYPE_GAME_ROTATION_VECTOR);
    161     }
    162 
    163     @Override
    164     protected void onCreate(Bundle savedInstanceState) {
    165         // set up sensors first, so activitySetUp has the state in place
    166         mSensorManager = (SensorManager) getApplicationContext().getSystemService(
    167                 Context.SENSOR_SERVICE);
    168         mSensor[ROTATION_VECTOR_INDEX] =
    169                 mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
    170         mSensor[GEOMAGNETIC_ROTATION_VECTOR_INDEX] =
    171                 mSensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
    172         mSensor[GAME_ROTATION_VECTOR_INDEX] =
    173                 mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
    174 
    175         super.onCreate(savedInstanceState);
    176 
    177         GLArrowSensorTestRenderer renderer =
    178                 new GLArrowSensorTestRenderer(this, Sensor.TYPE_ROTATION_VECTOR);
    179         mListener = renderer;
    180 
    181         initializeGlSurfaceView(renderer);
    182     }
    183 
    184     @Override
    185     protected void onPause() {
    186         super.onPause();
    187         mSensorManager.unregisterListener(mListener);
    188         mSensorManager.unregisterListener(this);
    189     }
    190 
    191     @Override
    192     protected void onResume() {
    193         super.onResume();
    194 
    195         // listener for rendering
    196         boolean renderListenerRegistered = false;
    197         for (int i = 0; (!renderListenerRegistered && i < MAX_SENSORS_AVAILABLE); ++i) {
    198             Sensor sensor = mSensor[i];
    199             if (sensor != null) {
    200                 renderListenerRegistered = mSensorManager
    201                         .registerListener(mListener, sensor, SensorManager.SENSOR_DELAY_GAME);
    202                 Log.v(LOG_TAG, "Renderer using sensor: " + sensor.getName());
    203             }
    204         }
    205 
    206         // listeners for testing
    207         for (int i = 0; i < MAX_SENSORS_AVAILABLE; ++i) {
    208             mSensorManager.registerListener(this, mSensor[i], SensorManager.SENSOR_DELAY_GAME);
    209         }
    210     }
    211 
    212     @Override
    213     public void onSensorChanged(SensorEvent event) {
    214         if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
    215             mLastEvent[ROTATION_VECTOR_INDEX] = event.values.clone();
    216         }
    217         if (event.sensor.getType() == Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR) {
    218             mLastEvent[GEOMAGNETIC_ROTATION_VECTOR_INDEX] = event.values.clone();
    219         }
    220         if (event.sensor.getType() == Sensor.TYPE_GAME_ROTATION_VECTOR) {
    221             mLastEvent[GAME_ROTATION_VECTOR_INDEX] = event.values.clone();
    222         }
    223     }
    224 
    225     @Override
    226     public void onAccuracyChanged(Sensor sensor, int accuracy) {
    227     }
    228 
    229     private static double findMaxComponentDegrees(float[] vec) {
    230         float maxComponent = 0;
    231         for (int i = 0; i < vec.length; i++) {
    232             float absComp = Math.abs(vec[i]);
    233             if (maxComponent < absComp) {
    234                 maxComponent = absComp;
    235             }
    236         }
    237         return Math.toDegrees(maxComponent);
    238     }
    239 }
    240