package com.mixpanel.android.viewcrawler;


import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;

import com.mixpanel.android.util.MPLog;

/* package */ class FlipGesture implements SensorEventListener {

    public interface OnFlipGestureListener {
        public void onFlipGesture();
    }

    public FlipGesture(OnFlipGestureListener listener) {
        mListener = listener;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // Samples may come in around 4 times per second

        final float[] smoothed = smoothXYZ(event.values);
        final int oldFlipState = mFlipState;

        final float totalGravitySquared =
                smoothed[0] * smoothed[0] + smoothed[1] * smoothed[1] + smoothed[2] * smoothed[2];

        final float minimumGravitySquared = MINIMUM_GRAVITY_FOR_FLIP * MINIMUM_GRAVITY_FOR_FLIP;
        final float maximumGravitySquared = MAXIMUM_GRAVITY_FOR_FLIP * MAXIMUM_GRAVITY_FOR_FLIP;

        mFlipState = FLIP_STATE_NONE;

        if (smoothed[2] > MINIMUM_GRAVITY_FOR_FLIP && smoothed[2] < MAXIMUM_GRAVITY_FOR_FLIP) {
            mFlipState = FLIP_STATE_UP;
        }

        if (smoothed[2] < -MINIMUM_GRAVITY_FOR_FLIP && smoothed[2] > -MAXIMUM_GRAVITY_FOR_FLIP) {
            mFlipState = FLIP_STATE_DOWN;
        }

        // Might overwrite current state, which is what we want.
        if (totalGravitySquared < minimumGravitySquared ||
                totalGravitySquared > maximumGravitySquared) {
            mFlipState = FLIP_STATE_NONE;
        }

        if (oldFlipState != mFlipState) {
            mLastFlipTime = event.timestamp;
        }

        // We need at least 1/4 seconds to recognize an UP or DOWN state
        // We need at least 1 seconds to recognize a NONE state

        final long flipDurationNanos = event.timestamp - mLastFlipTime;

        switch (mFlipState) {
            case FLIP_STATE_DOWN:
                if (flipDurationNanos > MINIMUM_UP_DOWN_DURATION && mTriggerState == TRIGGER_STATE_NONE) {
                    MPLog.v(LOGTAG, "Flip gesture begun");
                    mTriggerState = TRIGGER_STATE_BEGIN;
                }
                break;
            case FLIP_STATE_UP:
                if (flipDurationNanos > MINIMUM_UP_DOWN_DURATION && mTriggerState == TRIGGER_STATE_BEGIN) {
                    MPLog.v(LOGTAG, "Flip gesture completed");
                    mTriggerState = TRIGGER_STATE_NONE;
                    mListener.onFlipGesture();
                }
                break;
            case FLIP_STATE_NONE:
                if (flipDurationNanos > MINIMUM_CANCEL_DURATION && mTriggerState != TRIGGER_STATE_NONE) {
                    MPLog.v(LOGTAG, "Flip gesture abandoned");
                    mTriggerState = TRIGGER_STATE_NONE;
                }
                break;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        ; // Do nothing
    }

    private float[] smoothXYZ(final float[] samples) {
        // Note that smoothing doesn't depend on sample timestamp!
        for (int i = 0; i < 3; i++) {
            final float oldVal = mSmoothed[i];
            mSmoothed[i] = oldVal + (ACCELEROMETER_SMOOTHING * (samples[i] - oldVal));
        }

        return mSmoothed;
    }

    private int mTriggerState = -1;
    private int mFlipState = FLIP_STATE_NONE;
    private long mLastFlipTime = -1;
    private final float[] mSmoothed = new float[3];
    private final OnFlipGestureListener mListener;

    private static final float MINIMUM_GRAVITY_FOR_FLIP = 9.8f - 2.0f;
    private static final float MAXIMUM_GRAVITY_FOR_FLIP = 9.8f + 2.0f;

    // 1000000000 one second
    //  250000000 one quarter second
    private static final long MINIMUM_UP_DOWN_DURATION = 250000000;
    private static final long MINIMUM_CANCEL_DURATION = 1000000000;

    private static final int FLIP_STATE_UP = -1;
    private static final int FLIP_STATE_NONE = 0;
    private static final int FLIP_STATE_DOWN = 1;

    private static final int TRIGGER_STATE_NONE = 0;
    private static final int TRIGGER_STATE_BEGIN = 1;

    // Higher is noisier but more responsive, 1.0 to 0.0
    private static final float ACCELEROMETER_SMOOTHING = 0.7f;

    private static final String LOGTAG = "MixpanelAPI.FlipGesture";
}

@@ -3188,16 +3188,39 @@
 oldVal =
+ i %3C mSmoothed.length ?
  mSmooth
@@ -3224,16 +3224,20 @@
 othed%5Bi%5D
+ : 0
 ;%0A      

Update FlipGesture.java (#600)