/*
 * Copyright (C) 2008 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;

import com.android.cts.util.TimeoutReq;

import junit.framework.Assert;

import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorEventListener2;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.hardware.cts.helpers.SensorCtsHelper;
import android.hardware.cts.helpers.SensorNotSupportedException;
import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEventListener;
import android.hardware.cts.helpers.TestSensorManager;
import android.hardware.cts.helpers.sensoroperations.ParallelSensorOperation;
import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
import android.hardware.cts.helpers.sensorverification.EventGapVerification;
import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class SensorTest extends SensorTestCase {
    private static final String TAG = "SensorTest";

    // Test only SDK defined sensors. Any sensors with type > 100 are ignored.
    private static final int MAX_OFFICIAL_ANDROID_SENSOR_TYPE = 100;

    private PowerManager.WakeLock mWakeLock;
    private SensorManager mSensorManager;
    private TestSensorManager mTestSensorManager;
    private NullTriggerEventListener mNullTriggerEventListener;
    private NullSensorEventListener mNullSensorEventListener;
    private Sensor mTriggerSensor;
    private List<Sensor> mSensorList;

    @Override
    protected void setUp() throws Exception {
        Context context = getContext();
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);

        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        mNullTriggerEventListener = new NullTriggerEventListener();
        mNullSensorEventListener = new NullSensorEventListener();

        mSensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        assertNotNull("SensorList was null.", mSensorList);
        if (mSensorList.isEmpty()) {
            // several devices will not have sensors, so we need to skip the tests in those cases
            throw new SensorTestStateNotSupportedException(
                    "Sensors are not available in the system.");
        }

        mWakeLock.acquire();
    }

    @Override
    protected void tearDown(){
        if (mSensorManager != null) {
            // SensorManager will check listener and status, so just unregister listener
            mSensorManager.unregisterListener(mNullSensorEventListener);
            if (mTriggerSensor != null) {
                mSensorManager.cancelTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
                mTriggerSensor = null;
            }
        }

        if (mTestSensorManager != null) {
            mTestSensorManager.unregisterListener();
            mTestSensorManager = null;
        }

        if (mWakeLock != null && mWakeLock.isHeld()) {
            mWakeLock.release();
        }
    }

    @SuppressWarnings("deprecation")
    public void testSensorOperations() {
        // Because we can't know every sensors unit details, so we can't assert
        // get values with specified values.
        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        boolean hasAccelerometer = getContext().getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_SENSOR_ACCELEROMETER);
        // accelerometer sensor is optional
        if (hasAccelerometer) {
            assertEquals(Sensor.TYPE_ACCELEROMETER, sensor.getType());
            assertSensorValues(sensor);
        } else {
            assertNull(sensor);
        }

        sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
        boolean hasStepCounter = getContext().getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_SENSOR_STEP_COUNTER);
        // stepcounter sensor is optional
        if (hasStepCounter) {
            assertEquals(Sensor.TYPE_STEP_COUNTER, sensor.getType());
            assertSensorValues(sensor);
        } else {
            assertNull(sensor);
        }

        sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
        boolean hasStepDetector = getContext().getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_SENSOR_STEP_DETECTOR);
        // stepdetector sensor is optional
        if (hasStepDetector) {
            assertEquals(Sensor.TYPE_STEP_DETECTOR, sensor.getType());
            assertSensorValues(sensor);
        } else {
            assertNull(sensor);
        }

        sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
        boolean hasHeartRate = getContext().getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_SENSOR_HEART_RATE);
        // heartrate sensor is optional
        if (hasHeartRate) {
            assertEquals(Sensor.TYPE_HEART_RATE, sensor.getType());
            assertSensorValues(sensor);
        } else {
            assertNull(sensor);
        }

        sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        boolean hasCompass = getContext().getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_SENSOR_COMPASS);
        // compass sensor is optional
        if (hasCompass) {
            assertEquals(Sensor.TYPE_MAGNETIC_FIELD, sensor.getType());
            assertSensorValues(sensor);
        } else {
            assertNull(sensor);
        }

        sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        // orientation sensor is required if the device can physically implement it
        if (hasCompass && hasAccelerometer) {
            assertEquals(Sensor.TYPE_ORIENTATION, sensor.getType());
            assertSensorValues(sensor);
        }

        sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
        // temperature sensor is optional
        if (sensor != null) {
            assertEquals(Sensor.TYPE_TEMPERATURE, sensor.getType());
            assertSensorValues(sensor);
        }
    }

    public void testValuesForAllSensors() {
        for (Sensor sensor : mSensorList) {
            assertSensorValues(sensor);
        }
    }

    private void hasOnlyOneWakeUpSensorOrEmpty(List<Sensor> sensors) {
        if (sensors == null || sensors.isEmpty()) return;
        if (sensors.size() > 1) {
            fail("More than one " + sensors.get(0).getName() + " defined.");
            return;
        }
        assertTrue(sensors.get(0).getName() + " defined as non-wake-up sensor",
                sensors.get(0).isWakeUpSensor());
    }

    // Some sensors like proximity, significant motion etc. are defined as wake-up sensors by
    // default. Check if the wake-up flag is set correctly.
    public void testWakeUpFlags() {
        final int TYPE_WAKE_GESTURE = 23;
        final int TYPE_GLANCE_GESTURE = 24;
        final int TYPE_PICK_UP_GESTURE = 25;

        hasOnlyOneWakeUpSensorOrEmpty(mSensorManager.getSensorList(Sensor.TYPE_SIGNIFICANT_MOTION));
        hasOnlyOneWakeUpSensorOrEmpty(mSensorManager.getSensorList(TYPE_WAKE_GESTURE));
        hasOnlyOneWakeUpSensorOrEmpty(mSensorManager.getSensorList(TYPE_GLANCE_GESTURE));
        hasOnlyOneWakeUpSensorOrEmpty(mSensorManager.getSensorList(TYPE_PICK_UP_GESTURE));

        List<Sensor> proximity_sensors = mSensorManager.getSensorList(Sensor.TYPE_PROXIMITY);
        if (proximity_sensors.isEmpty()) return;
        boolean hasWakeUpProximitySensor = false;
        for (Sensor sensor : proximity_sensors) {
            if (sensor.isWakeUpSensor()) {
                hasWakeUpProximitySensor = true;
                break;
            }
        }
        assertTrue("No wake-up proximity sensors implemented", hasWakeUpProximitySensor);
    }

    public void testGetDefaultSensorWithWakeUpFlag() {
        // With wake-up flags set to false, the sensor returned should be a non wake-up sensor.
        for (Sensor sensor : mSensorList) {
            Sensor curr_sensor = mSensorManager.getDefaultSensor(sensor.getType(), false);
            if (curr_sensor != null) {
                assertFalse("getDefaultSensor wakeup=false returns a wake-up sensor" +
                        curr_sensor.getName(),
                        curr_sensor.isWakeUpSensor());
            }

            curr_sensor = mSensorManager.getDefaultSensor(sensor.getType(), true);
            if (curr_sensor != null) {
                assertTrue("getDefaultSensor wake-up returns non wake sensor" +
                        curr_sensor.getName(),
                        curr_sensor.isWakeUpSensor());
            }
        }
    }

    public void testSensorStringTypes() {
        for (Sensor sensor : mSensorList) {
            if (sensor.getType() < MAX_OFFICIAL_ANDROID_SENSOR_TYPE &&
                    !sensor.getStringType().startsWith("android.sensor.")) {
                fail("StringType not set correctly for android defined sensor " +
                        sensor.getName() + " " + sensor.getStringType());
            }
        }
    }

    public void testRequestTriggerWithNonTriggerSensor() {
        mTriggerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (mTriggerSensor == null) {
            throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
        }
        boolean  result = mSensorManager.requestTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
        assertFalse(result);
    }

    public void testCancelTriggerWithNonTriggerSensor() {
        mTriggerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (mTriggerSensor == null) {
            throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
        }
        boolean result = mSensorManager.cancelTriggerSensor(mNullTriggerEventListener, mTriggerSensor);
        assertFalse(result);
    }

    public void testRegisterWithTriggerSensor() {
        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
        if (sensor == null) {
            throw new SensorNotSupportedException(Sensor.TYPE_SIGNIFICANT_MOTION);
        }
        boolean result = mSensorManager.registerListener(
                mNullSensorEventListener,
                sensor,
                SensorManager.SENSOR_DELAY_NORMAL);
        assertFalse(result);
    }

    public void testRegisterTwiceWithSameSensor() {
        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (sensor == null) {
            throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER);
        }

        boolean result = mSensorManager.registerListener(mNullSensorEventListener, sensor,
                SensorManager.SENSOR_DELAY_NORMAL);
        assertTrue(result);

        result = mSensorManager.registerListener(mNullSensorEventListener, sensor,
                SensorManager.SENSOR_DELAY_NORMAL);
        assertFalse(result);
    }

    // TODO: remove when parametized tests are supported and EventTimestampSynchronization
    //       verification is added to default verifications
    @TimeoutReq(minutes=60)
    public void testSensorTimeStamps() throws Exception {
        ArrayList<Throwable> errorsFound = new ArrayList<>();
        for (Sensor sensor : mSensorList) {
            // test both continuous and batching mode sensors
            verifyLongActivation(sensor, 0 /* maxReportLatencyUs */, errorsFound);
            verifyLongActivation(sensor, (int) TimeUnit.SECONDS.toMicros(10), errorsFound);
        }
        assertOnErrors(errorsFound);
    }

    // TODO: remove when parameterized tests are supported (see SensorBatchingTests.java)
    @TimeoutReq(minutes=20)
    public void testBatchAndFlush() throws Exception {
        SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
        ArrayList<Throwable> errorsFound = new ArrayList<>();
        for (Sensor sensor : mSensorList) {
            verifyRegisterListenerCallFlush(sensor, null /* handler */, errorsFound);
        }
        assertOnErrors(errorsFound);
    }

    /**
     * Verifies that sensor events arrive in the given message queue (Handler).
     */
    @TimeoutReq(minutes=10)
    public void testBatchAndFlushWithHandler() throws Exception {
        SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
        Sensor sensor = null;
        for (Sensor s : mSensorList) {
            if (s.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS) {
                sensor = s;
                break;
            }
        }
        if (sensor == null) {
            throw new SensorTestStateNotSupportedException(
                    "There are no Continuous sensors in the device.");
        }

        TestSensorEnvironment environment = new TestSensorEnvironment(
                getContext(),
                sensor,
                SensorManager.SENSOR_DELAY_FASTEST,
                (int) TimeUnit.SECONDS.toMicros(5));
        mTestSensorManager = new TestSensorManager(environment);

        HandlerThread handlerThread = new HandlerThread("sensorThread");
        handlerThread.start();
        Handler handler = new Handler(handlerThread.getLooper());
        TestSensorEventListener listener = new TestSensorEventListener(environment, handler);

        CountDownLatch eventLatch = mTestSensorManager.registerListener(listener, 1);
        listener.waitForEvents(eventLatch, 1, true);
        CountDownLatch flushLatch = mTestSensorManager.requestFlush();
        listener.waitForFlushComplete(flushLatch, true);
        listener.assertEventsReceivedInHandler();
    }

    /**
     *  Explicit testing the SensorManager.registerListener(SensorEventListener, Sensor, int, int).
     */
    @TimeoutReq(minutes=10)
    public void testBatchAndFlushUseDefaultHandler() throws Exception {
        SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
        Sensor sensor = null;
        for (Sensor s : mSensorList) {
            if (s.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS) {
                sensor = s;
                break;
            }
        }
        if (sensor == null) {
            throw new SensorTestStateNotSupportedException(
                    "There are no Continuous sensors in the device.");
        }

        TestSensorEnvironment environment = new TestSensorEnvironment(
                getContext(),
                sensor,
                SensorManager.SENSOR_DELAY_FASTEST,
                (int) TimeUnit.SECONDS.toMicros(5));
        mTestSensorManager = new TestSensorManager(environment);

        TestSensorEventListener listener = new TestSensorEventListener(environment, null);

        // specifyHandler <= false, use the SensorManager API without Handler parameter
        CountDownLatch eventLatch = mTestSensorManager.registerListener(listener, 1, false);
        listener.waitForEvents(eventLatch, 1, true);
        CountDownLatch flushLatch = mTestSensorManager.requestFlush();
        listener.waitForFlushComplete(flushLatch, true);
        listener.assertEventsReceivedInHandler();
    }

    // TODO: after L release move to SensorBatchingTests and run in all sensors with default
    //       verifications enabled
    public void testBatchAndFlushWithMultipleSensors() throws Exception {
        SensorCtsHelper.sleep(3, TimeUnit.SECONDS);
        final int maxSensors = 3;
        final int maxReportLatencyUs = (int) TimeUnit.SECONDS.toMicros(10);
        List<Sensor> sensorsToTest = new ArrayList<Sensor>();
        for (Sensor sensor : mSensorList) {
            if (sensor.getReportingMode() == Sensor.REPORTING_MODE_CONTINUOUS) {
                sensorsToTest.add(sensor);
                if (sensorsToTest.size()  == maxSensors) break;
            }
        }
        final int numSensorsToTest = sensorsToTest.size();
        if (numSensorsToTest == 0) {
            return;
        }

        StringBuilder builder = new StringBuilder();
        ParallelSensorOperation parallelSensorOperation = new ParallelSensorOperation();
        for (Sensor sensor : sensorsToTest) {
            TestSensorEnvironment environment = new TestSensorEnvironment(
                    getContext(),
                    sensor,
                    shouldEmulateSensorUnderLoad(),
                    SensorManager.SENSOR_DELAY_FASTEST,
                    maxReportLatencyUs);
            FlushExecutor executor = new FlushExecutor(environment, 500 /* eventCount */);
            parallelSensorOperation.add(new TestSensorOperation(environment, executor));
            builder.append(sensor.getName()).append(", ");
        }

        Log.i(TAG, "Testing batch/flush for sensors: " + builder);
        parallelSensorOperation.execute(getCurrentTestNode());
    }

    private void assertSensorValues(Sensor sensor) {
        assertTrue("Max range must be positive. Range=" + sensor.getMaximumRange()
                + " " + sensor.getName(), sensor.getMaximumRange() >= 0);
        assertTrue("Max power must be positive. Power=" + sensor.getPower() + " " +
                sensor.getName(), sensor.getPower() >= 0);
        assertTrue("Max resolution must be positive. Resolution=" + sensor.getResolution() +
                " " + sensor.getName(), sensor.getResolution() >= 0);
        assertNotNull("Vendor name must not be null " + sensor.getName(), sensor.getVendor());
        assertTrue("Version must be positive version=" + sensor.getVersion() + " " +
                sensor.getName(), sensor.getVersion() > 0);
        int fifoMaxEventCount = sensor.getFifoMaxEventCount();
        int fifoReservedEventCount = sensor.getFifoReservedEventCount();
        assertTrue(fifoMaxEventCount >= 0);
        assertTrue(fifoReservedEventCount >= 0);
        assertTrue(fifoReservedEventCount <= fifoMaxEventCount);
        if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
            assertTrue("One shot sensors should have zero FIFO Size " + sensor.getName(),
                    sensor.getFifoMaxEventCount() == 0);
            assertTrue("One shot sensors should have zero FIFO Size "  + sensor.getName(),
                    sensor.getFifoReservedEventCount() == 0);
        }
    }

    @SuppressWarnings("deprecation")
    public void testLegacySensorOperations() {
        final SensorManager mSensorManager =
                (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);

        // We expect the set of sensors reported by the new and legacy APIs to be consistent.
        int sensors = 0;
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
            sensors |= SensorManager.SENSOR_ACCELEROMETER;
        }
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
            sensors |= SensorManager.SENSOR_MAGNETIC_FIELD;
        }
        if (mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION) != null) {
            sensors |= SensorManager.SENSOR_ORIENTATION | SensorManager.SENSOR_ORIENTATION_RAW;
        }
        assertEquals(sensors, mSensorManager.getSensors());
    }

    /**
     * Verifies that a continuous sensor produces events that have timestamps synchronized with
     * {@link SystemClock#elapsedRealtimeNanos()}.
     */
    private void verifyLongActivation(
            Sensor sensor,
            int maxReportLatencyUs,
            ArrayList<Throwable> errorsFound) throws InterruptedException {
        if (sensor.getReportingMode() != Sensor.REPORTING_MODE_CONTINUOUS) {
            return;
        }

        try {
            TestSensorEnvironment environment = new TestSensorEnvironment(
                    getContext(),
                    sensor,
                    shouldEmulateSensorUnderLoad(),
                    SensorManager.SENSOR_DELAY_FASTEST,
                    maxReportLatencyUs);
            TestSensorOperation operation =
                    TestSensorOperation.createOperation(environment, 20, TimeUnit.SECONDS);
            operation.addVerification(EventGapVerification.getDefault(environment));
            operation.addVerification(EventOrderingVerification.getDefault(environment));
            operation.addVerification(
                    EventTimestampSynchronizationVerification.getDefault(environment));

            Log.i(TAG, "Running timestamp test on: " + sensor.getName());
            operation.execute(getCurrentTestNode());
        } catch (InterruptedException e) {
            // propagate so the test can stop
            throw e;
        } catch (Throwable e) {
            errorsFound.add(e);
            Log.e(TAG, e.getMessage());
        }
    }

    /**
     * Verifies that a client can listen for events, and that
     * {@link SensorManager#flush(SensorEventListener)} will trigger the appropriate notification
     * for {@link SensorEventListener2#onFlushCompleted(Sensor)}.
     */
    private void verifyRegisterListenerCallFlush(
            Sensor sensor,
            Handler handler,
            ArrayList<Throwable> errorsFound)
            throws InterruptedException {
        if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
            return;
        }

        try {
            TestSensorEnvironment environment = new TestSensorEnvironment(
                    getContext(),
                    sensor,
                    shouldEmulateSensorUnderLoad(),
                    SensorManager.SENSOR_DELAY_FASTEST,
                    (int) TimeUnit.SECONDS.toMicros(10));
            FlushExecutor executor = new FlushExecutor(environment, 500 /* eventCount */);
            TestSensorOperation operation = new TestSensorOperation(environment, executor, handler);

            Log.i(TAG, "Running flush test on: " + sensor.getName());
            operation.execute(getCurrentTestNode());
        } catch (InterruptedException e) {
            // propagate so the test can stop
            throw e;
        } catch (Throwable e) {
            errorsFound.add(e);
            Log.e(TAG, e.getMessage());
        }
    }

    private void assertOnErrors(List<Throwable> errorsFound) {
        if (!errorsFound.isEmpty()) {
            StringBuilder builder = new StringBuilder();
            for (Throwable error : errorsFound) {
                builder.append(error.getMessage()).append("\n");
            }
            Assert.fail(builder.toString());
        }
    }

    /**
     * A delegate that drives the execution of Batch/Flush tests.
     * It performs several operations in order:
     * - registration
     * - for continuous sensors it first ensures that the FIFO is filled
     *      - if events do not arrive on time, an assert will be triggered
     * - requests flush of sensor data
     * - waits for {@link SensorEventListener2#onFlushCompleted(Sensor)}
     *      - if the event does not arrive, an assert will be triggered
     */
    private class FlushExecutor implements TestSensorOperation.Executor {
        private final TestSensorEnvironment mEnvironment;
        private final int mEventCount;

        public FlushExecutor(TestSensorEnvironment environment, int eventCount) {
            mEnvironment = environment;
            mEventCount = eventCount;
        }

        /**
         * Consider only continuous mode sensors for testing register listener.
         *
         * For on-change sensors, we only use
         * {@link TestSensorManager#registerListener(TestSensorEventListener)} to associate the
         * listener with the sensor. So that {@link TestSensorManager#requestFlush()} can be
         * invoked on it.
         */
        @Override
        public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
                throws InterruptedException {
            int sensorReportingMode = mEnvironment.getSensor().getReportingMode();
            try {
                CountDownLatch eventLatch = sensorManager.registerListener(listener, mEventCount);
                if (sensorReportingMode == Sensor.REPORTING_MODE_CONTINUOUS) {
                    listener.waitForEvents(eventLatch, mEventCount, true);
                }
                CountDownLatch flushLatch = sensorManager.requestFlush();
                listener.waitForFlushComplete(flushLatch, true);
            } finally {
                sensorManager.unregisterListener();
            }
        }
    }

    private class NullTriggerEventListener extends TriggerEventListener {
        @Override
        public void onTrigger(TriggerEvent event) {}
    }

    private class NullSensorEventListener implements SensorEventListener {
        @Override
        public void onSensorChanged(SensorEvent event) {}

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {}
    }

}
